EN/CH Mode
BRUCE_FE JS Interview Notes - Hand-written Promise.all Implementation
Learn how to hand-write JavaScript Promise.all method implementation, master techniques for handling multiple asynchronous tasks, and enhance frontend interview competitiveness.
EN/CH Mode
Lazy to read articles? Then watch videos!
Promise.all Method Overview
Promise.all
is an important method in JavaScript for handling multiple Promises. It takes an array of Promises (or iterable object) and returns a new Promise that resolves when all input Promises resolve successfully, or rejects immediately when any Promise is rejected.
Characteristics of Promise.all
- 1.
Parallel Execution
: All Promises start executing simultaneously - 2.
Wait for All
: Wait for all Promises to complete - 3.
One Failure, All Fail
: If any Promise rejects, the entire operation immediately rejects - 4.
Maintain Result Order
: Result array order matches input array order - 5.
Non-Promise Values
: Automatically wrapped with Promise.resolve()
Hand-writing Promise.all
implementation is a popular topic in frontend interviews, testing understanding of Promises, asynchronous processing, and array operations.
Native Promise.all Usage
Before implementation, let's look at the native usage of Promise.all
:
// Create three Promises
const promise1 = Promise.resolve(1);
const promise2 = new Promise((resolve) => setTimeout(() => resolve(2), 1000));
const promise3 = Promise.resolve(3);
// Use Promise.all to process three Promises in parallel
Promise.all([promise1, promise2, promise3])
.then(results => {
console.log(results); // [1, 2, 3] (order matches input array)
})
.catch(error => {
console.error('At least one Promise was rejected', error);
});
// Example of handling rejection
const promise4 = Promise.resolve(4);
const promise5 = Promise.reject('Error occurred');
const promise6 = Promise.resolve(6);
Promise.all([promise4, promise5, promise6])
.then(results => {
console.log('This will not execute');
})
.catch(error => {
console.error(error); // 'Error occurred' (from rejected promise5)
});
Hand-written Promise.all Implementation
Now let's implement the Promise.all
method:
// Basic Promise.all implementation
function promiseAll(promises) {
// Check if input is iterable
if (!promises[Symbol.iterator]) {
return Promise.reject(new TypeError('Parameter must be iterable'));
}
// Convert input to array
const promiseArray = Array.from(promises);
const len = promiseArray.length;
// Create a new Promise
return new Promise((resolve, reject) => {
// Empty array returns empty result directly
if (len === 0) {
return resolve([]);
}
// Array to store results
const results = new Array(len);
// Count of completed Promises
let resolvedCount = 0;
// Process each Promise
promiseArray.forEach((promise, index) => {
// Wrap non-Promise values as Promises
Promise.resolve(promise)
.then(value => {
// Store results in original order
results[index] = value;
resolvedCount++;
// When all Promises complete, resolve the overall Promise
if (resolvedCount === len) {
resolve(results);
}
})
.catch(error => {
// If any Promise rejects, immediately reject the overall Promise
reject(error);
});
});
});
}
Let's test this implementation:
// Test cases
const p1 = Promise.resolve(1);
const p2 = new Promise(resolve => setTimeout(() => resolve(2), 100));
const p3 = 3; // Non-Promise value, will be automatically wrapped
promiseAll([p1, p2, p3])
.then(results => {
console.log(results); // [1, 2, 3]
})
.catch(error => {
console.error(error);
});
// Test error case
const p4 = Promise.resolve(4);
const p5 = Promise.reject('Failure');
const p6 = Promise.resolve(6);
promiseAll([p4, p5, p6])
.then(results => {
console.log('This will not execute');
})
.catch(error => {
console.error(error); // 'Failure'
});