JavaScript
medium
very high
mid
Promise.all vs allSettled vs race vs any — when do you use each?
all = fail-fast aggregation. allSettled = collect every outcome. race = first to settle (resolve or reject). any = first to *resolve*, ignores rejections until all fail.
7 min read·~12 min to think through
Four combinators with very different semantics:
Promise.all([p1, p2])— resolves with an array of values once all resolve. Rejects immediately with the first rejection. Other promises keep running but their results are dropped. Use when you need every result and a partial result is meaningless.Promise.allSettled([p1, p2])— always resolves, with an array of{ status: 'fulfilled'|'rejected', value|reason }. Use when partial success is fine — dashboards, telemetry, fan-out where you want to render whatever returned.Promise.race([p1, p2])— settles with the first promise to settle, whether resolve or reject. Use for timeouts: race the work againstsetTimeout(reject).Promise.any([p1, p2])— resolves with the first fulfilled promise; only rejects (withAggregateError) if every input rejects. Use for redundancy: the same request to multiple mirrors.
Key gotcha: Promise.all does not cancel the losers. If you start 5 fetches and one rejects, the other 4 still run, still consume bandwidth, and their unhandled rejections can warn the console — wire them through AbortController if you need real cancellation.
Code
Follow-up questions
- •How would you implement Promise.all from scratch?
- •Why doesn't Promise.all cancel the other promises on rejection?
- •When would you prefer allSettled over all in a UI dashboard?
Common mistakes
- •Using `Promise.all` for independent panels and crashing the whole UI on one failure.
- •Forgetting that `race` resolves on rejection too — and being surprised when an error wins.
- •Assuming losers in `all` are cancelled (they aren't).
Performance considerations
- •Concurrency control: `Promise.all(arr.map(fetch))` with a 1000-item array opens 1000 sockets. Use a pool/limit (`p-limit`) for bounded concurrency.
Edge cases
- •`Promise.all([])` resolves with `[]` immediately. `Promise.any([])` rejects with empty `AggregateError`.
- •`Promise.race([])` returns a forever-pending promise — easy way to leak.
Real-world examples
- •Server-side rendering: `Promise.all` for required data, `allSettled` for nice-to-have widgets so a slow widget can't block the page.
Senior engineer discussion
Senior signal: cancellation strategy with AbortController, structured concurrency patterns, and the difference between an unhandled rejection (process-level event) and a swallowed one inside `all`.