Implement Promise.all from scratch
Implement promiseAll(promises) that mirrors Promise.all: it returns a promise that fulfills with an array of results in input order, or rejects as soon as any input rejects. Requirements: results must keep their original index regardless of settle order; an empty input fulfills immediately with []; non-promise values are allowed and pass through.
function promiseAll(promises) {
// your code here
}
Write the implementation.
Return a new Promise; if the input is empty, resolve [] at once. Track a remaining counter and a results array. For each item, Promise.resolve(item).then(value => { results[i] = value; if (--remaining === 0) resolve(results); }, reject). Writing by index keeps order despite settle timing, and the first reject settles the outer promise (later rejections are ignored).
- ✗Pushing results instead of writing by index, scrambling order on out-of-order settling
- ✗Forgetting the empty-input case, which never resolves without an early
[] - ✗Not wrapping items in
Promise.resolve, so plain non-promise values break.then
- →How would you change this to implement
Promise.allSettledinstead? - →Why is wrapping each item in
Promise.resolveneeded for non-promise values?
Solution
A remaining counter plus index writes preserve order; the first reject settles everything.
function promiseAll(promises) {
return new Promise((resolve, reject) => {
const items = [...promises];
const results = new Array(items.length);
let remaining = items.length;
if (remaining === 0) return resolve(results); // empty input
items.forEach((item, i) => {
Promise.resolve(item).then((value) => { // wrap non-promises
results[i] = value; // write by index = order
if (--remaining === 0) resolve(results);
}, reject); // first reject settles the outer promise
});
});
}
How it works
Each item is wrapped in Promise.resolve, so plain values also get a .then. The result is written by index i, not push, so the output array order matches the input even when promises settle out of order. The remaining counter decrements on each fulfillment; when it hits zero the outer promise resolves. Any rejection calls reject immediately (later rejections are ignored because the promise is already settled). Empty input resolves with [] at once.