Understanding the different methods available for handling multiple promises in JavaScript is crucial for effective asynchronous programming. Each of the methods—Promise.all(), Promise.allSettled(), Promise.race(), and Promise.any()—serves a unique purpose and has distinct behaviors when managing promises. Below, we will explore each method in detail, including practical examples, best practices, and common mistakes to avoid.
Promise.all() takes an iterable of promises and returns a single Promise that resolves when all of the promises in the iterable have resolved or rejects if any of the promises reject. The resolved value is an array containing the results of the input promises, in the same order as they were passed.
const promise1 = Promise.resolve(3);
const promise2 = 42; // Non-promise value
const promise3 = new Promise((resolve, reject) => setTimeout(resolve, 100, 'foo'));
Promise.all([promise1, promise2, promise3])
.then(values => {
console.log(values); // Output: [3, 42, 'foo']
})
.catch(error => {
console.error('One of the promises rejected:', error);
});
Promise.allSettled() also takes an iterable of promises but returns a single Promise that resolves after all of the given promises have either resolved or rejected. The resolved value is an array of objects that each describe the outcome of each promise.
const promise1 = Promise.resolve(3);
const promise2 = Promise.reject('error');
const promise3 = new Promise((resolve) => setTimeout(resolve, 100, 'foo'));
Promise.allSettled([promise1, promise2, promise3])
.then(results => {
console.log(results);
/*
Output:
[
{ status: 'fulfilled', value: 3 },
{ status: 'rejected', reason: 'error' },
{ status: 'fulfilled', value: 'foo' }
]
*/
});
Promise.race() takes an iterable of promises and returns a single Promise that resolves or rejects as soon as one of the promises in the iterable resolves or rejects, with the value or reason from that promise.
const promise1 = new Promise((resolve) => setTimeout(resolve, 500, 'first'));
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'second'));
Promise.race([promise1, promise2])
.then(value => {
console.log(value); // Output: 'second'
})
.catch(error => {
console.error('One of the promises rejected:', error);
});
Promise.any() takes an iterable of Promise objects and, unlike the other methods, it resolves as soon as one of the promises in the iterable fulfills. If no promises fulfill (i.e., all are rejected), it rejects with an AggregateError, a new subclass of Error that groups together multiple errors.
const promise1 = Promise.reject('error1');
const promise2 = Promise.reject('error2');
const promise3 = Promise.resolve('success');
Promise.any([promise1, promise2, promise3])
.then(value => {
console.log(value); // Output: 'success'
})
.catch(error => {
console.error('All promises were rejected:', error);
});
In summary, understanding the differences between these promise methods allows developers to choose the right tool for their asynchronous programming needs. Each method has its use cases, advantages, and potential pitfalls, making it essential to grasp their behaviors thoroughly.