Promise Combinators
Promise combinators coordinate multiple asynchronous operations with different settlement and failure semantics. JavaScript provides `Promise.all`, `Promise.allSettled`, `Promise.race`, and `Promise.any` for common coordination patterns.
`Promise.all` waits for every input promise to fulfill and produces their values in input order. If any input rejects, the returned promise rejects, although the other operations are not automatically canceled.
`Promise.allSettled` waits until every input has settled, regardless of whether each one fulfilled or rejected. It returns an array describing each result with a `status` plus either `value` or `reason`, making it useful when you need a complete outcome report.
`Promise.race` settles as soon as the first input promise settles. The first result can therefore be either fulfillment or rejection, which makes it useful for timeout patterns and first-response behavior.
`Promise.any` fulfills when the first input promise fulfills. It ignores earlier rejections unless every input rejects; in that case it rejects with an `AggregateError` containing the rejection reasons.
All four methods accept an iterable of values or promises. Non-promise values are treated as already fulfilled, and the resulting promise is always asynchronous even when the inputs are already settled.
Key points
- `Promise.all` requires every input to fulfill and preserves input order.
- `Promise.allSettled` reports every input outcome without failing early.
- `Promise.race` settles on the first fulfillment or rejection.
- `Promise.any` waits for the first fulfillment and rejects only when all inputs reject.
- Combinators coordinate promises but do not automatically cancel underlying asynchronous work.
Interview questions
When would you use `Promise.race`?
I use `Promise.race` when the first promise to settle should determine the result. The winner may be either a fulfillment or a rejection. A common pattern is racing an operation against a timeout promise. The race itself does not cancel the promises that lose.
What is the difference between `Promise.all` and `Promise.allSettled`?
`Promise.all` fulfills only if every input fulfills and returns their values in input order. If one rejects, the combined promise rejects. `Promise.allSettled` waits for every input to finish and always fulfills with an outcome record for each input. I would use `all` when every operation is required and `allSettled` when I need to inspect every result.
How does `Promise.any` differ from `Promise.race`?
`Promise.any` is interested specifically in the first successful fulfillment. Rejections are ignored while other candidates remain, so it is useful when multiple alternatives can satisfy the same requirement. If every input rejects, `Promise.any` rejects with an `AggregateError`. `Promise.race`, by contrast, reacts to the first settlement regardless of whether it succeeds or fails.
Do promise combinators run asynchronous operations in parallel?
They can coordinate operations that have already been started or are started before being passed to the combinator. For example, creating several promises and then passing them to `Promise.all` allows their underlying asynchronous work to proceed concurrently. The combinator itself does not make inherently sequential work parallel. Also, JavaScript's concurrency model and the underlying APIs determine how that work actually executes.
What happens to the other promises when `Promise.all` rejects?
The combined `Promise.all` promise rejects as soon as an input rejects, but the other operations continue unless something explicitly cancels them. This distinction matters for network requests, timers, and other resources that may still consume work after the caller observes the rejection. If cancellation is needed, the underlying operations must support it, such as requests controlled by `AbortController`. Therefore, fail-fast result handling and cancellation are separate concerns.