The four combinators take an iterable of promises (plain values count as fulfilled) and return one promise. The operations already run concurrently; a combinator only decides when to report, and results keep the input order.
| Method | Settles when | Fulfills with | Rejects with |
|---|---|---|---|
| all() (ES2015) | all fulfill, or one rejects | array of values | the first reason |
| race() (ES2015) | the first input settles | that value | that reason |
| allSettled() (ES2020) | every input settles | {status, value | reason} objects | never |
| any() (ES2021) | one fulfills, or all reject | the first value | AggregateError with .errors |
const delay = (ms, value, fail) => new Promise((resolve, reject) =>
setTimeout(() => (fail ? reject(new Error(value)) : resolve(value)), ms));
const jobs = () => [delay(30, "slow"), delay(10, "fast"), delay(20, "broken", true)];
console.log(await Promise.all(jobs()).catch(err => `all() rejected: ${err.message}`));
console.log(await Promise.race(jobs()), await Promise.any(jobs()));
console.log((await Promise.allSettled(jobs())).map(result => result.status));all() rejected: broken fast fast [ 'fulfilled', 'fulfilled', 'rejected' ]
Use all() when every result is required, allSettled() for independent widgets, any() for redundant mirrors and race() for timeouts. None of them cancels the losers, so pass an AbortSignal (Practical Asynchrony) when work should stop. With an empty iterable, all() and allSettled() fulfill with [], any() rejects, and race() stays pending forever.