Promise.race()
Settles with the first promise to settle, whether that outcome is a fulfillment or a rejection.
Promise.race(iterable)- Added in JavaScript ES2015
Parameters
| Parameter | Type | Description |
|---|---|---|
$iterable | Iterable | An iterable, such as an Array, of promises. Values are awaited, so other thenables are resolved too; non-thenables are passed through as-is and count as already settled. |
Return value
PromiseA Promise that asynchronously settles with the eventual state of the first input to settle — fulfilling if that one fulfilled, rejecting if it rejected. It stays pending forever if the iterable is empty.
Errors
TypeError if the argument is not iterable.
Promise.race() settles with whichever input settles first, and it does not care how it settled. A rejection that arrives first rejects the race, which is exactly the property that makes the timeout idiom work: race the real operation against a promise that rejects after N milliseconds and the loser is irrelevant.
The losers keep running
Nothing is cancelled. The slower operation continues to completion and still consumes its resources; its eventual outcome, fulfillment or rejection, is simply discarded. A losing rejection is not reported as unhandled, because race() attached its own handler to every input when it iterated them. If your work supports real cancellation, pair the race with an AbortController and abort the loser yourself.
Watch the already-settled inputs
Non-promise values and already-settled promises count as settled at the point race() iterates them, so the earliest such item in the array wins immediately — order in the iterable matters here in a way it does not for all(). Putting a plain value first makes the race a foregone conclusion.
Edge case
Promise.race([]) returns a promise that stays pending forever. Awaiting it hangs silently, with no error to tell you why.
Example
When to use it
- Reject an operation that has not finished within a deadline
- Take whichever of two redundant sources answers first
- Stop waiting on a long poll when a shutdown signal fires
- Surface the first error out of several concurrent operations
Frequently asked questions
How do I add a timeout to a promise?
Race it against a promise that rejects on a timer: Promise.race([work(), timeout(5000)]). Remember the work continues after the timeout fires unless you cancel it separately with something like an AbortController.
Does Promise.race cancel the slower promises?
No. Promises cannot be cancelled; the losers run to completion and their results are simply discarded.
What happens with Promise.race([])?
You get a promise that never settles. Awaiting it hangs indefinitely with no error, so guard against empty arrays before racing.
More examples
A rejection wins just as easily
The first race rejects after 5ms even though a success was on the way — race has no preference for fulfillment. The second shows a plain value winning outright, because it is already settled when race() reaches it.
const delay = (ms, v) => new Promise((r) => setTimeout(() => r(v), ms));
const boom = (ms, m) => new Promise((_, rj) => setTimeout(() => rj(new Error(m)), ms));
console.log(
await Promise.race([boom(5, "fast failure"), delay(50, "slow success")]).catch(
(e) => "rejected: " + e.message,
),
);
console.log(await Promise.race(["already here", delay(0, "too late")]));The loser carries on
quick wins the race at 15ms, but the ticker is untouched by losing — it keeps firing until its fifth tick and then resolves normally, showing that race() short-circuits only the combined result, never the work itself.
let ticks = 0;
const ticker = new Promise((res) => {
const id = setInterval(() => {
if (++ticks === 5) { clearInterval(id); res("ticker done"); }
}, 10);
});
const quick = new Promise((res) => setTimeout(() => res("quick done"), 15));
console.log("winner:", await Promise.race([ticker, quick]));
console.log("loser eventually:", await ticker, "ticks:", ticks);
Discussion