Promise.allSettled / race / any Polyfills
Implement all three Promise utility methods.
Promise.myAllSettled(promises)
- Never rejects
- Resolves with
{ status: "fulfilled", value }or{ status: "rejected", reason }for each input
Promise.myRace(promises)
- Settles as soon as the first promise settles (resolve or reject)
Promise.myAny(promises)
- Resolves with the first fulfilled value
- Only rejects if all promises reject, via
AggregateError
Examples
Promise.myAllSettled([Promise.resolve(1), Promise.reject('err')])
.then(console.log)[{ status: 'fulfilled', value: 1 }, { status: 'rejected', reason: 'err' }]Promise.myRace([
new Promise(r => setTimeout(() => r('slow'), 200)),
new Promise(r => setTimeout(() => r('fast'), 50)),
]).then(console.log)fastNotes
- Mental map: all (every success), allSettled (every outcome), race (first either way), any (first success)
Hints
Editorial: Promise.allSettled / race / any Polyfills
Implementing Promise.allSettled, Promise.race, and Promise.any
These three are variations on Promise.all. Interviewers ask them together because the differences test whether you understand promise settling vs. memorizing one pattern.
Promise.allSettled
Waits for every promise to settle and never rejects. Resolves with an array of outcome objects.
Promise.myAllSettled = function (promises) { return new Promise((resolve) => { const items = Array.from(promises); const results = new Array(items.length); let settledCount = 0; if (items.length === 0) { resolve(results); return; } items.forEach((item, index) => { Promise.resolve(item) .then( (value) => (results[index] = { status: "fulfilled", value }), (reason) => (results[index] = { status: "rejected", reason }) ) .finally(() => { settledCount++; if (settledCount === items.length) resolve(results); }); }); }); };
Key point: There is no reject in the executor at all. It always resolves. The outcome shape is { status: "fulfilled", value } or { status: "rejected", reason }.
Promise.race
Settles as soon as the first promise settles, whether resolve or reject.
Promise.myRace = function (promises) { return new Promise((resolve, reject) => { for (const item of promises) { Promise.resolve(item).then(resolve, reject); } }); };
Key point: It's short because once resolve or reject is called, the Promise spec ignores all subsequent calls. The first settlement wins automatically — no bookkeeping needed.
Promise.any
Resolves with the first fulfilled value. Only rejects if every promise rejects, via AggregateError. This is the inverse of all.
Promise.myAny = function (promises) { return new Promise((resolve, reject) => { const items = Array.from(promises); const errors = new Array(items.length); let rejectedCount = 0; if (items.length === 0) { reject(new AggregateError([], "All promises were rejected")); return; } items.forEach((item, index) => { Promise.resolve(item).then(resolve, (error) => { errors[index] = error; rejectedCount++; if (rejectedCount === items.length) { reject(new AggregateError(errors, "All promises were rejected")); } }); }); }); };
Key point: Track rejections by index (for AggregateError ordering) and only reject when all have failed.
Mental map of all four
| Method | Resolves when | Rejects when |
|---|---|---|
all | All fulfill | First rejection |
allSettled | All settle (never rejects) | — |
race | First to settle (either way) | First to settle (either way) |
any | First to fulfill | All reject → AggregateError |