How do you implement Promise.all from scratch?
Promise.all takes an array of promises and resolves to an array of their results — or rejects as soon as any one fails.
The approach:
Return a new Promise.
Track a results array and a counter of how many have resolved.
As each input promise resolves, store its value at the matching index and increment the counter.
When the counter equals the input length, resolve with the results array.
If any promise rejects, reject the outer promise immediately.
Key details: preserve input order by index (not completion order), and resolve right away for an empty array.
function promiseAll(promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument must be an array'));
}
if (promises.length === 0) {
return resolve([]); // Empty array resolves immediately
}
const results = new Array(promises.length);
let resolvedCount = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise) // Handle non-promise values
.then(value => {
results[index] = value; // Maintain order
resolvedCount++;
if (resolvedCount === promises.length) {
resolve(results); // All done
}
})
.catch(reject); // First rejection rejects the whole thing
});
});
}
// Test
const p1 = Promise.resolve(1);
const p2 = new Promise(r => setTimeout(() => r(2), 100));
const p3 = Promise.resolve(3);
promiseAll([p1, p2, p3]).then(console.log); // [1, 2, 3]
promiseAll([p1, Promise.reject('error'), p3]).catch(console.log); // 'error'
promiseAll([1, 2, 3]).then(console.log); // [1, 2, 3] (non-promises wrapped)A counter (resolvedCount) tracks completed promises. results[index] stores results in original order (not completion order). Promise.resolve wraps non-promise values. When resolvedCount reaches the total, resolve with all results.
Any rejection immediately calls reject (fail-fast). Empty array resolves with [].
This is a very common coding interview question. Key details: maintain order (results[index], not push), handle non-promises (Promise.resolve wrapper), empty array edge case, and fail-fast on first rejection.
The counter approach (not a loop checking all) is the correct solution.