Start independent work before waiting for it
await first(); await second(); starts second only after first fulfills. That is right when the second needs the first result. If they are independent, call both first, then use Promise.all to await their combined results. This is overlapping work, not a promise that JavaScript runs two CPU-heavy loops on separate cores.
Promise.all preserves input order in its result array, even if operations finish in another order. It rejects when one input rejects. It does not automatically cancel the other operations. A partially completed write may already have happened, so do not confuse rejection with rollback.
Promise.allSettled waits for every outcome. Each record has status “fulfilled” and value, or status “rejected” and reason. Use it when partial results are useful, such as a dashboard with independent panels. For a list that must be complete, an all-or-nothing failure can be clearer.
Always choose the product behavior before selecting the promise utility. A catch that replaces every error with an empty array makes failures look like “no results.” Keep the difference visible. The tests below use immediately settled local promises, so their output does not depend on a remote machine’s speed.
Predict and trace
Write the output before running. Follow the values through each call; if your prediction differs, identify the first step that surprised you.
async function main() {
// This result needs both requests to succeed.
const values = await Promise.all([
Promise.resolve("books"),
Promise.resolve("tags")
]);
console.log(values.join(", "));
// Here we keep each outcome, including the failure.
const outcomes = await Promise.allSettled([
Promise.resolve(2),
Promise.reject(new Error("Unavailable"))
]);
console.log(outcomes[0].status);
console.log(outcomes[1].status);
console.log(outcomes[1].reason.message);
}
main();Check your prediction
books, tags
fulfilled
rejected
UnavailableThe rejected promise is observed by allSettled rather than left unhandled.
Starting work and awaiting work are different steps
Promise.all cannot start work hidden inside an uncalled function. The calls create promises; the coordination helper then observes their outcomes. Sequential await is correct for dependencies, but needlessly serializes independent operations.
The result array preserves input order. A rejection does not undo side effects from other operations and does not cancel them. Use allSettled when every outcome is needed, and inspect each status before accessing value or reason.
async function main() {
const events = [];
async function task(name) {
events.push(name);
return name;
}
const a = task("A");
const b = task("B");
console.log(events.join(","));
console.log((await Promise.all([b, a])).join(","));
}
main();Check your prediction
A,B
B,A Call order created A then B, but the input order supplied to all is B then A. Completion timing is a third concept; do not confuse any of the three.
async function main() {
const outcomes = await Promise.allSettled([
Promise.resolve(0),
Promise.reject("offline")
]);
for (const item of outcomes) {
console.log(item.status === "fulfilled" ? item.value : item.reason);
}
}
main();Check your prediction
0
offline Zero is a successful value. Branching on status preserves it, while a truthiness test on value could mistake it for failure.
Try the rule on new inputs
Try one rejection with Promise.all and explain what its caller receives. Then use allSettled and retain the successful zero. Avoid adding timers merely to guess completion order; controlled promises will make schedule tests precise.
Build it yourself
Promise Coordination: practise
Write successfulValues(promises), awaiting all outcomes and returning only fulfilled values in input order. Print 2, 5 for one rejection between two successes.
// Inspect status before reading value.Hint 1: the idea
AllSettled records are ordinary objects with different fields by status.
Hint 2: a first step
Filter fulfilled outcomes, then map their value properties.
Show one solution
async function main() {
async function successfulValues(promises) {
const outcomes = await Promise.allSettled(promises);
return outcomes
.filter(item => item.status === "fulfilled")
.map(item => item.value);
}
const values = await successfulValues([
Promise.resolve(2),
Promise.reject(new Error("bad")),
Promise.resolve(5)
]);
console.log(values.join(", "));
}
main();2, 5Try an empty input and all failures. This helper deliberately discards failure information; adapt it to return a separate error count when the interface needs to report omissions.
Test a changed requirement
Try an empty input and all failures. This helper deliberately discards failure information; adapt it to return a separate error count when the interface needs to report omissions.
Explain before moving on
Which operations may run after Promise.all rejects? When is partial success misleading?
Completion is saved in this browser only. It does not measure mastery.