Q19: Implement a polyfill for Promise.all().
Answer
Promise.all() accepts an iterable of promises or other values and returns a promise that fulfills when every input fulfills. Results preserve the original input order, regardless of completion order. It rejects when an input rejects.
if (!Promise.myAll) {
Promise.myAll = function (iterable) {
return new Promise((resolve, reject) => {
let items;
try {
items = Array.from(iterable);
} catch (error) {
reject(error);
return;
}
const results = new Array(items.length);
let remaining = items.length;
if (remaining === 0) {
resolve(results);
return;
}
items.forEach((item, index) => {
Promise.resolve(item).then(
value => {
results[index] = value;
remaining--;
if (remaining === 0) {
resolve(results);
}
},
reject
);
});
});
};
}
Promise.myAll([
Promise.resolve(1),
2,
Promise.resolve(3)
]).then(console.log);
// [1, 2, 3]
Explanation
- Convert the iterable into an array.
- Create a results array with the same number of slots.
- Resolve each input using
Promise.resolve(). - Store each fulfilled value at its original index.
- Resolve the outer promise when every input fulfills.
- Reject the outer promise if an input rejects.
Interview edge cases
- An empty iterable produces a fulfilled promise containing an empty array.
- Non-promise values are accepted.
- Results preserve input order, not completion order.
- Native
Promise.all()has detailed iterable and constructor semantics that a production-quality polyfill must preserve.
Preserving result order
const first = new Promise(resolve => setTimeout(() => resolve("first"), 100));
const second = Promise.resolve("second");
Promise.myAll([first, second]).then(console.log);
// ["first", "second"]💡 The second promise can fulfill first, but Promise.all returns values in input order.
Key Takeaways
- Promise.all fulfills only when every input fulfills and rejects when an input rejects.
- Result ordering follows input order, not completion order.