Differences between handling multiple asynchronous operations
Promise.all (all succeed or reject on first failure), Promise.allSettled (wait for all, get every outcome), Promise.race (first to settle, success or failure), Promise.any (first to succeed). Plus sequential await-in-loop vs parallel. Choose by: need all? tolerate failures? need just one?
When you have multiple async operations, the question is how their results and failures combine. The toolbox:
Promise.all — all succeed, or fail fast
Runs them in parallel, resolves with an array of all results — but rejects immediately if any one rejects (the others keep running but you get the first error).
const [user, posts, prefs] = await Promise.all([getUser(), getPosts(), getPrefs()]);Use when you need all results and any failure means the whole thing fails (loading a page that needs all three).
Promise.allSettled — wait for all, tolerate failures
Runs in parallel, always waits for every promise, resolves with an array of { status, value } / { status, reason } — never rejects.
const results = await Promise.allSettled([getA(), getB(), getC()]);
// results: [{status:"fulfilled", value}, {status:"rejected", reason}, ...]Use when you want every outcome and partial failure is OK — fetch 10 widgets, render the 8 that succeeded.
Promise.race — first to settle (either way)
Resolves or rejects with the first promise to settle, whether it succeeded or failed.
await Promise.race([fetchData(), timeout(5000)]); // timeout patternUse for timeouts or "whichever responds first."
Promise.any — first to succeed
Resolves with the first fulfilled promise; ignores rejections; only rejects (with an AggregateError) if all fail.
await Promise.any([fetchFromMirror1(), fetchFromMirror2()]); // first working mirrorUse for fallbacks / redundancy — first source that works.
Sequential vs parallel
Separate axis: await in a for loop runs them one after another (each waits for the previous) — necessary when each step depends on the last, but slow otherwise. Independent operations should run in parallel (kick them all off, then Promise.all). A classic perf mistake is await-ing in a loop when the iterations are independent.
The decision table
| Need | Tool |
|---|---|
| All results, fail if any fails | Promise.all |
| All outcomes, tolerate failures | Promise.allSettled |
| First to settle (success or fail) | Promise.race |
| First success, fallback chain | Promise.any |
| Each depends on the previous | sequential await |
The framing
"It comes down to how results and failures combine. Promise.all — parallel, all-or-nothing, rejects on the first failure. Promise.allSettled — parallel, waits for everything, gives you every outcome and never rejects, for when partial failure is fine. Promise.race — first to settle either way, the timeout pattern. Promise.any — first to succeed, for fallbacks. And separately, sequential await-in-a-loop versus parallel — only go sequential when each step depends on the last; awaiting independent operations in a loop is the classic perf bug."
Follow-up questions
- •When would you use allSettled over all?
- •What's the difference between race and any?
- •Why is awaiting independent operations in a loop a problem?
- •What error does Promise.any throw when everything fails?
Common mistakes
- •Using Promise.all when partial failure should be tolerated (one failure kills everything).
- •await-ing in a loop for independent operations — sequential when it could be parallel.
- •Confusing race (first to settle) with any (first to succeed).
- •Forgetting Promise.all's other promises still run after the first rejection.
Performance considerations
- •Running independent async ops in parallel (Promise.all/allSettled) instead of sequentially can cut total time from the sum of latencies to the max — often the single biggest async perf win. race with a timeout bounds worst-case latency.
Edge cases
- •Empty array passed to Promise.all (resolves immediately) vs Promise.any (rejects).
- •Promise.race with an empty array never settles.
- •Unhandled rejections from the 'losing' promises in race/any.
- •All promises rejecting in Promise.any → AggregateError.
Real-world examples
- •Promise.all to load all data a page needs; allSettled for a dashboard of independent widgets.
- •Promise.race for fetch-with-timeout; Promise.any for trying multiple API mirrors.