Implementing Promise.allSettled in JavaScript
Let’s dive into implementing Promise.allSettled
, a method that was introduced in ECMAScript 2020. This method 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.
What is Promise.allSettled
?
Promise.allSettled
is used to handle multiple promises and obtain the result of each promise, regardless of whether it was resolved or rejected. Unlike Promise.all
, which rejects as soon as one of the promises rejects, Promise.allSettled
waits for all promises to settle and returns an array of objects describing the outcome of each promise.
Real Interview Insights
Interviewers might ask you to:
- Implement
Promise.allSettled
from scratch. - Explain the differences between
Promise.all
andPromise.allSettled
. - Discuss scenarios where
Promise.allSettled
is more appropriate thanPromise.all
.
Implementing Promise.allSettled
Here's a basic implementation of Promise.allSettled
:
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 };
})
.catch(reason => {
resultArray[index] = { status: 'rejected', reason };
})
.finally(() => {
settledCounter++;
if (settledCounter === promisesCount) {
resolve(resultArray);
}
});
});
});
}
Explanation:
- Input Validation: Ensure the input is an array. If not, throw a
TypeError
. - Result Array: Use an array to store the result objects.
- Settled Counter: Track the number of promises that have settled.
- Promises Processing: For each promise, handle both fulfillment and rejection, and update the result array with appropriate status and value or reason.
- Final Resolution: Resolve the main promise once all promises have settled.
Practical Example
Consider an example with a mix of resolved and rejected promises:
const promise1 = Promise.resolve(1);
const promise2 = Promise.reject('Error occurred');
const promise3 = Promise.resolve(3);
promiseAllSettled([promise1, promise2, promise3])
.then(results => console.log(results));
// Output:
// [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: 'Error occurred' },
// { status: 'fulfilled', value: 3 }
// ]
In this example:
- The
promiseAllSettled
function handles each promise, regardless of its outcome, and returns an array describing the result of each promise.
Advanced Use Case: Handling Large Number of Promises
For scenarios with a large number of promises, performance considerations are important. The implementation provided is straightforward, but you should be aware of:
- Memory Usage: Handling a large number of promises may consume significant memory.
- Execution Time: Ensuring that the implementation is optimized for performance.
Coding Challenge: Promise.allSettled
with Custom Settled Statuses
Challenge: Modify the promiseAllSettled
function to include additional custom statuses or metadata for 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, timestamp: new Date().toISOString() };
})
.catch(reason => {
resultArray[index] = { status: 'rejected', reason, timestamp: new Date().toISOString() };
})
.finally(() => {
settledCounter++;
if (settledCounter === promisesCount) {
resolve(resultArray);
}
});
});
});
}
// Example usage with custom statuses
promiseAllSettled([promise1, promise2, promise3])
.then(results => console.log(results));
In this challenge:
- Enhance the
promiseAllSettled
function to include a timestamp or additional metadata for each promise result.