Instead of waiting for all, sometimes you want the first.
Promise.race: first to settle
Promise.race settles (resolves or rejects) as soon as the first promise settles.
const wait = (ms, value) => new Promise(resolve => setTimeout(() => resolve(value), ms));
Promise.race([wait(300, "slow"), wait(100, "fast")])
.then(winner => console.log(winner)); // → fast
The classic use: a timeout
const wait = (ms, value) => new Promise(resolve => setTimeout(() => resolve(value), ms));
function withTimeout(promise, ms) {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error("Timed out after " + ms + " ms")), ms)
);
return Promise.race([promise, timeout]);
}
withTimeout(wait(500, "data"), 100)
.then(v => console.log(v))
.catch(e => console.log(e.message)); // → Timed out after 100 ms
(For fetch, the better way to cancel the request itself is AbortController, see AbortController.)
Promise.any: first to succeed
Promise.any resolves with the first promise that fulfils, and ignores rejections, unless all reject, in which case it rejects with an AggregateError.
const wait = (ms, value) => new Promise(resolve => setTimeout(() => resolve(value), ms));
const fail = ms => new Promise((_, reject) => setTimeout(() => reject(new Error("failed")), ms));
Promise.any([fail(50), wait(200, "backup server"), wait(300, "other server")])
.then(value => console.log(value)); // → backup server
A good use: try several mirrors or sources and take whichever answers first successfully.
const fail = ms => new Promise((_, reject) => setTimeout(() => reject(new Error("down")), ms));
Promise.any([fail(10), fail(20)]).catch(error => {
console.log(error.name); // → AggregateError
console.log(error.errors.length); // → 2
});
The four methods side by side
| Method | Settles when | Rejects when |
|---|---|---|
Promise.all | all fulfil | any rejects |
Promise.allSettled | all settle | never |
Promise.race | the first settles | the first one rejects |
Promise.any | the first fulfils | all reject |
Race does not cancel
The slower promises keep running in the background. race just stops caring about them. Cancelling the actual work needs an AbortController (for fetch) or similar.
Support
Promise.any and Promise.allSettled are supported by all current browsers. If you must support very old ones, check the compatibility tables first.