Promise.all, allSettled, race
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.
| Combinator | Fulfills when | Rejects when | Result |
|---|---|---|---|
Promise.all | All fulfill | Any one rejects (immediately) | Array of values, in order |
Promise.allSettled | All settle | Never | Array of { status, value or reason } |
Promise.race | First to settle fulfills | First to settle rejects | The first result |
Promise.any | First to fulfill | All reject | The 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
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
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
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
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
1// ✗ Sequential by mistake: total time = sum of all2for (const id of ids) {3 results.push(await fetchItem(id));4}5 6// ✓ Parallel: total time = the slowest one7const results = await Promise.all(ids.map(fetchItem));And with Promise.all, one failure hides every other result:
1await Promise.all([ok(), fails(), ok()]); // rejects, you lose the two good resultsIf 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.allinside an effect or a loader. - Use
allSettledfor dashboards where each widget can fail on its own. - Use
racefor a timeout, and pair it withAbortControllerfor real cancellation. - With TanStack Query, you usually run several
useQuerycalls instead, and each handles its own loading and error state.
Summary
1all → all succeed or fail fast, results keep input order2allSettled → waits for everyone, never rejects, gives a status per promise3race → first to settle decides, good for timeouts4any → first success wins, fails only if all fail5Independent work → run in parallel, not with await one by one6Partial failure is OK → allSettled7Cancellation → AbortController, race alone does not cancelNext, a topic that quietly causes many React bugs: whether JavaScript copies a value or shares it.