Back to JavaScript
JavaScript
easy
mid

What are the differences between approaches for 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?

4 min read·~6 min to think through

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).

js
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.

js
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.

js
await Promise.race([fetchData(), timeout(5000)]); // timeout pattern

Use 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.

js
await Promise.any([fetchFromMirror1(), fetchFromMirror2()]); // first working mirror

Use 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

NeedTool
All results, fail if any failsPromise.all
All outcomes, tolerate failuresPromise.allSettled
First to settle (success or fail)Promise.race
First success, fallback chainPromise.any
Each depends on the previoussequential 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.

Senior engineer discussion

Seniors map each combinator to its semantics (fail-fast, tolerate-all, first-settled, first-success), separate the sequential-vs-parallel axis, and call out awaiting independent work in a loop as a common avoidable slowdown.

Related questions