Suggest an editImprove this articleRefine the answer for “Promise.all, promise.race, promise.allsettled, promise.any”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Promise.all, Promise.race, Promise.allSettled, Promise.any** - four static methods for coordinating multiple promises, each with a different strategy for handling success and failure. ```javascript Promise.all([p1, p2, p3]); // all succeed or fails on first rejection Promise.race([p1, p2]); // first settled promise wins Promise.allSettled([p1, p2, p3]); // waits for all, never rejects Promise.any([p1, p2, p3]); // first success, or AggregateError if all fail ``` **Key:** `all` and `race` short-circuit on the first relevant event; `allSettled` and `any` always process every promise to completion.Shown above the full answer for quick recall.Answer (EN)Image**Promise.all, Promise.race, Promise.allSettled, and Promise.any** are four static methods on the Promise constructor, each coordinating a group of promises with a different strategy for what counts as "done." ## Theory ### TL;DR - `Promise.all` waits for every promise to succeed; the first rejection cancels everything - `Promise.race` returns whatever settles first, fulfilled or rejected - `Promise.allSettled` always resolves with the outcome of every promise, no matter what - `Promise.any` returns the first success; only rejects if every input fails, via `AggregateError` - Decision rule: need all results? `all`. Need fastest? `race`. Need full picture? `allSettled`. Need first success? `any` ### Quick example ```javascript const p1 = Promise.resolve("fast"); const p2 = new Promise(r => setTimeout(() => r("medium"), 100)); const p3 = Promise.reject("boom"); Promise.all([p1, p2, p3]).catch(e => console.log(e)); // "boom" Promise.race([p1, p2, p3]).then(console.log); // "fast" Promise.allSettled([p1, p2, p3]).then(console.log); // [{status:"fulfilled",value:"fast"},{status:"fulfilled",value:"medium"},{status:"rejected",reason:"boom"}] Promise.any([p3, p1, p2]).then(console.log); // "fast" ``` `p1` is already resolved. `p3` rejects immediately. `Promise.all` bails on `p3`. `Promise.race` never reaches `p3` because `p1` wins first. `Promise.allSettled` reports all three. `Promise.any` skips the rejection and returns the first success. ### Key difference `all` and `race` short-circuit: `all` stops at the first rejection, `race` stops at the first settlement of any kind. `allSettled` and `any` keep going regardless. `allSettled` collects everything; `any` stops the moment it finds one success. That boundary is where most bugs appear in production async code. ### When to use - All results are required to proceed: `Promise.all` (parallel API calls, config loading) - Timeout pattern: `Promise.race` paired with a delay promise that rejects after N ms - Partial failures are acceptable: `Promise.allSettled` (dashboards, batch saves, logging) - First available wins: `Promise.any` (CDN failover, trying multiple servers) - Combined: wrap `Promise.any` inside `Promise.race` to add a global timeout on top of failover logic ### Comparison table | Method | Short-circuits? | When it settles | On success | On failure | Added in | |--------|----------------|-----------------|------------|------------|----------| | `Promise.all` | Yes, first rejection | All fulfill OR one rejects | `Array` of values (ordered) | First rejection reason | ES2015 | | `Promise.race` | Yes, first settlement | Any promise settles | First settled value | First settled reason | ES2015 | | `Promise.allSettled` | No | All promises settle | `Array` of `{status, value/reason}` | Never rejects | ES2020 | | `Promise.any` | Yes, first fulfillment | First fulfills OR all reject | First fulfilled value | `AggregateError` with all reasons | ES2021 | ### How the engine handles this V8 implements all four as native C++ functions inside `PromiseConstructor`. `Promise.all` iterates the input, stores results by index, and triggers rejection the moment any promise rejects without waiting for the rest. `Promise.allSettled` uses the same counter logic but increments it for both fulfilled and rejected outcomes, so it never short-circuits. `Promise.race` and `Promise.any` set a winner flag on the first qualifying settlement. Non-promise values get wrapped in `Promise.resolve()` automatically, which is why `Promise.race([1, slowPromise])` resolves with `1` immediately. ### Common mistakes **Expecting Promise.all to collect all errors** ```javascript // Wrong: only the first rejection comes through Promise.all([failA(), failB()]).catch(e => { console.log(e); // One error. The other is gone. }); // Fix: use allSettled and filter const results = await Promise.allSettled([failA(), failB()]); const errors = results .filter(r => r.status === "rejected") .map(r => r.reason); ``` **Using Promise.race without a timeout creates hangs** ```javascript // Wrong: if neither promise ever settles, this hangs forever Promise.race([slowPromise, anotherSlowPromise]).then(handle); // Fix: always pair race with a timeout promise const withTimeout = (p, ms) => Promise.race([ p, new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), ms) ) ]); ``` **Not handling AggregateError from Promise.any** ```javascript // Wrong: e.message is generic, individual reasons are lost Promise.any([fail1, fail2]).catch(e => console.log(e.message)); // Fix: check e.errors for individual reasons Promise.any([fail1, fail2]).catch(e => { if (e instanceof AggregateError) { console.log(e.errors); // array of all rejection reasons } }); ``` **Passing non-promise values and losing intent** ```javascript Promise.race([1, slowPromise]).then(console.log); // 1, immediately ``` This works because `1` wraps to `Promise.resolve(1)`. But it signals nothing about intent. Keep all inputs as actual promises. **Mutating allSettled results in place** ```javascript // Confusing: mutates result objects directly results.forEach(r => { r.value = r.value?.toUpperCase(); }); // Clear: map to new objects const updated = results.map(r => r.status === "fulfilled" ? { ...r, value: r.value.toUpperCase() } : r ); ``` ### Real-world usage - React Query uses `Promise.all` internally for `useQueries` to batch parallel requests - Next.js `getStaticProps` runs data fetchers in parallel via `Promise.all` - SWR calls `Promise.allSettled` when running `mutate` on multiple cache keys - Express middleware chains use `Promise.race` for per-route timeouts on external calls - Node.js `dns.promises` batch lookups rely on `Promise.all` ### Follow-up questions **Q:** What happens when you pass an empty array to each method? **A:** `Promise.all([])` and `Promise.allSettled([])` resolve immediately with `[]`. `Promise.race([])` never settles. `Promise.any([])` rejects immediately with an `AggregateError`. **Q:** `Promise.race([p1, p2])` where `p1` rejects first. What happens to `p2`? **A:** `race` rejects immediately with p1's reason. `p2` keeps running in the background but its result is ignored. The chain has already moved on. **Q:** Why does Promise.any throw AggregateError instead of the last rejection reason? **A:** Because when all inputs fail, there is no single "last" that carries more meaning than the others. `AggregateError` collects every reason in `e.errors`, so nothing is lost. Access individual reasons via `e.errors[0]`, `e.errors[1]`, and so on. **Q:** How would you polyfill Promise.any for environments without ES2021? **A:** Invert the logic of `Promise.all`. Track rejections in an array and a fulfilled counter. Resolve on first fulfillment. If all reject, throw `new AggregateError(rejectionsArray, "All promises were rejected")`. **Q:** What are the memory implications of allSettled vs all when processing thousands of promises? **A:** `allSettled` holds all result objects in memory until every promise settles. `all` can release references earlier on rejection. At scale this difference matters; chunk large batches regardless of which method you use. ## Examples ### Parallel data fetching with Promise.all ```javascript async function fetchUserDashboard(userId) { // All three requests go out at the same time const [user, posts, comments] = await Promise.all([ fetch(`/api/users/${userId}`).then(r => r.json()), fetch(`/api/posts?userId=${userId}`).then(r => r.json()), fetch(`/api/comments?userId=${userId}`).then(r => r.json()) ]); return { user, posts, comments }; } ``` If any of the three endpoints fail, the whole function throws. That is exactly right here: showing a profile with missing pieces would be worse than showing an error page. ### Timeout pattern with Promise.race ```javascript const withTimeout = (promise, ms) => Promise.race([ promise, new Promise((_, reject) => setTimeout(() => reject(new Error(`Timed out after ${ms}ms`)), ms) ) ]); app.get("/data", async (req, res) => { try { const data = await withTimeout(fetchFromDatabase(), 3000); res.json(data); } catch (err) { res.status(503).json({ error: err.message }); } }); ``` I add this wrapper to every Express route that calls an external service. Without it, one slow dependency can hold a request open for minutes. ### CDN failover with Promise.any ```javascript async function loadAsset(assetName) { const cdnUrls = [ `https://cdn1.example.com/${assetName}`, `https://cdn2.example.com/${assetName}`, `https://cdn3.example.com/${assetName}` ]; try { return await Promise.any( cdnUrls.map(url => fetch(url).then(r => { if (!r.ok) throw new Error(`${url}: ${r.status}`); return url; }) ) ); } catch (err) { // err.errors contains each individual failure reason throw new Error("All CDN endpoints failed"); } } ``` ### Graceful degradation with Promise.allSettled ```javascript async function loadDashboard() { const [userResult, statsResult, feedResult] = await Promise.allSettled([ fetchUser(), // Required fetchStats(), // Optional fetchActivityFeed() // Optional ]); if (userResult.status === "rejected") { throw new Error("Cannot render dashboard without user data"); } return { user: userResult.value, stats: statsResult.status === "fulfilled" ? statsResult.value : null, feed: feedResult.status === "fulfilled" ? feedResult.value : [] }; } ``` Stats and feed failing is fine. User data failing is not. `allSettled` hands that decision back to the caller instead of making it for you.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.