Implementing Promise.all in JavaScript
What is Promise.all
?
Promise.all
is a method that takes an iterable (usually an array) of promises and returns a single promise that resolves when all of the promises in the iterable have resolved. It rejects if any of the promises in the iterable reject. The resolved value is an array of the resolved values of the input promises.
Real Interview Insights
Interviewers might ask you to:
- Implement a simplified version of
Promise.all
. - Explain how
Promise.all
handles both resolved and rejected promises. - Discuss the performance and use cases of
Promise.all
.
Implementing Promise.all
Let's start with a basic implementation of Promise.all
:
function promiseAll(promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Input must be an array'));
}
let resolvedCounter = 0;
const resultArray = [];
const promisesCount = promises.length;
if (promisesCount === 0) {
return resolve([]);
}
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then(value => {
resolvedCounter++;
resultArray[index] = value;
if (resolvedCounter === promisesCount) {
resolve(resultArray);
}
})
.catch(reject);
});
});
}
Explanation:
- Input Validation: Ensure the input is an array. If not, reject with a
TypeError
. - Counter and Result Array: Use a counter to track the number of resolved promises and an array to store the resolved values.
- Empty Array Check: If the input array is empty, resolve with an empty array immediately.
- Promise Resolution: Use
Promise.resolve
to handle both promise and non-promise values, ensuring all values are treated as promises.
Practical Example
Consider an example with multiple promises:
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);
promiseAll([promise1, promise2, promise3])
.then(results => console.log(results)) // Output: [1, 2, 3]
.catch(error => console.error(error));
In this example:
- The
promiseAll
function combines three resolved promises into a single promise that resolves with an array of their values.
Advanced Use Case: Handling Rejections
To handle scenarios where one or more promises reject, let's ensure our promiseAll
implementation properly rejects as soon as any promise rejects:
const failingPromise = new Promise((resolve, reject) => setTimeout(reject, 100, 'Failed'));
promiseAll([promise1, failingPromise, promise2])
.then(results => console.log(results))
.catch(error => console.error(error)); // Output: 'Failed'
In this scenario:
- The
promiseAll
function rejects as soon asfailingPromise
rejects, demonstrating proper handling of rejected promises.
Performance Considerations
While Promise.all
is efficient for waiting on multiple promises, be aware of the following:
- Concurrent Execution: All promises are started concurrently, which can be resource-intensive.
- Memory Usage: Storing all resolved values can consume significant memory for large arrays of promises.
Coding Challenge: Implement Promise.allSettled
Challenge: Implement Promise.allSettled
, a method that returns a promise that resolves after all of the given promises have either resolved or rejected, with an array of objects describing the outcome of each promise.
function promiseAllSettled(promises) {
return new Promise((resolve) => {
if (!Array.isArray(promises)) {
throw new TypeError('Input must be an array');
}
const resultArray = [];
let settledCounter = 0;
const promisesCount = promises.length;
if (promisesCount === 0) {
return resolve([]);
}
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then(value => {
resultArray[index] = { status: 'fulfilled', value };
settledCounter++;
if (settledCounter === promisesCount) {
resolve(resultArray);
}
})
.catch(reason => {
resultArray[index] = { status: 'rejected', reason };
settledCounter++;
if (settledCounter === promisesCount) {
resolve(resultArray);
}
});
});
});
}
// Example usage with allSettled
promiseAllSettled([promise1, failingPromise, promise2])
.then(results => console.log(results));
In this challenge:
- The
promiseAllSettled
function waits for all promises to settle and returns an array describing each promise's outcome.