On this page

Promise.all, allSettled, race

3 min read

Real screens load several things at once: the user, their orders, their settings. JavaScript gives you four tools to combine promises. Choosing the right one is a common interview question.

Definition

These are promise combinators. Each takes an array of promises and returns one promise. They differ in when that promise finishes and what it gives back.

CombinatorFulfills whenRejects whenResult
Promise.allAll fulfillAny one rejects (immediately)Array of values, in order
Promise.allSettledAll settleNeverArray of { status, value or reason }
Promise.raceFirst to settle fulfillsFirst to settle rejectsThe first result
Promise.anyFirst to fulfillAll rejectThe first success

Analogy: you send four friends to buy ingredients.

  • all: you cook only if all four come back. If one fails, you give up at once.
  • allSettled: you wait for all four and note who succeeded and who failed.
  • race: whoever comes back first, success or not, decides.
  • any: whoever comes back first with food wins. You fail only if all four fail.

Promise.all

js
1const [user, orders, settings] = await Promise.all([
2 fetchUser(),
3 fetchOrders(),
4 fetchSettings(),
5]);
  • Runs all promises in parallel.
  • The result array keeps the same order as the input, no matter who finishes first.
  • It fails fast. If any promise rejects, the combined promise rejects right away with that error. The other promises keep running, but their results are ignored.
  • Use it when you need all results to continue.

Promise.allSettled

js
1const results = await Promise.allSettled([fetchUser(), fetchOrders(), fetchAds()]);
2
3results.forEach((r) => {
4 if (r.status === "fulfilled") console.log(r.value);
5 else console.log("failed:", r.reason);
6});

It never rejects. You get a report for each promise. Use it when partial success is fine, like a dashboard where one failing widget should not break the others.

Promise.race

js
1const timeout = new Promise((_, reject) =>
2 setTimeout(() => reject(new Error("Timed out")), 5000)
3);
4const data = await Promise.race([fetch("/api/slow"), timeout]);

The most common use is a timeout. Note that race does not cancel the slower promise, it only stops waiting for it. To truly cancel a request, use an AbortController.

Promise.any

js
1const fastest = await Promise.any([fetchFromMirrorA(), fetchFromMirrorB()]);

Good for "try several sources, take the first good one". If all fail, it rejects with an AggregateError that holds every error.

Here Is What Breaks

js
1// ✗ Sequential by mistake: total time = sum of all
2for (const id of ids) {
3 results.push(await fetchItem(id));
4}
5
6// ✓ Parallel: total time = the slowest one
7const results = await Promise.all(ids.map(fetchItem));

And with Promise.all, one failure hides every other result:

js
1await Promise.all([ok(), fails(), ok()]); // rejects, you lose the two good results

If you need the good ones, use allSettled.

Parallel is not always right. Firing 1000 requests at once can overload a server or hit rate limits. Process them in batches instead.

In React

  • Load independent data for one screen with Promise.all inside an effect or a loader.
  • Use allSettled for dashboards where each widget can fail on its own.
  • Use race for a timeout, and pair it with AbortController for real cancellation.
  • With TanStack Query, you usually run several useQuery calls instead, and each handles its own loading and error state.

Summary

1all → all succeed or fail fast, results keep input order
2allSettled → waits for everyone, never rejects, gives a status per promise
3race → first to settle decides, good for timeouts
4any → first success wins, fails only if all fail
5Independent work → run in parallel, not with await one by one
6Partial failure is OK → allSettled
7Cancellation → AbortController, race alone does not cancel

Next, a topic that quietly causes many React bugs: whether JavaScript copies a value or shares it.

Next TopicReference vs Value & Copying