Introduction to Promise.all()
In an async sequence (Promise chain), only one async task is being coordinated at any given moment—step 2 strictly follows step 1, and step 3 strictly follows step 2. But what about doing two or more steps concurrently (aka “in parallel”)?
In classic programming terminology, a gate is a mechanism that waits on two or more parallel/concurrent tasks to complete before continuing. It doesn’t matter what order they finish in, just that all of them have to complete for the gate to open and let the flow control through.
In the Promise API, we call this pattern all([ .. ])
.
Promise.all([ .. ])
expects a single argument, an array, consisting generally of Promise instances. The promise returned from the Promise.all([ .. ])
call will receive a fulfillment message (msgs in this snippet) that is an array of all the fulfillment messages from the passed in promises, in the same order as specified (regardless of fulfillment order).
array
of values passed into Promise.all([ .. ])
can include Promises, thenables, or even immediate values. Each value in the list is essentially passed through Promise.resolve(..)
to make sure it’s a genuine Promise to be waited on, so an immediate value will just be normalized into a Promise for that value. If the array
is empty, the main Promise is immediately fulfilled.The main promise returned from Promise.all([ .. ])
will only be fulfilled if and when all its constituent promises are fulfilled. If any one of those promises is instead rejected, the main Promise.all([ .. ])
promise is immediately rejected, discarding all results from any other promises.
Remember to always attach a rejection/error handler to every promise, even and especially the one that comes back from Promise.all([ .. ])
.
Using the promise.all
method
The Promise.all
method takes an iterable, such as an array, containing promises as its argument, and returns a new promise. If all of the promises in the iterable are resolved, the new promise will be resolved with an array containing the resolved values of the input promises. If any of the promises in the iterable are rejected, the new promise will be rejected with the value of the first rejected promise.
Here is an example of how to use the Promise.all
method to handle the results of multiple asynchronous operations:
let promise1 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(1);
}, 1000);
});
let promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(2);
}, 2000);
});
let promise3 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(3);
}, 3000);
});
Promise.all([promise1, promise2, promise3])
.then(function (values) {
console.log(values);
})
.catch(function (error) {
console.error(error);
});
Output
[ 1, 2, 3 ]
In this example, the Promise.all
method is used to create a new promise that will be resolved when all of the input promises (promise1, promise2, and promise3) have been resolved.
The then
method is used to specify a callback function that will be executed when the new promise is resolved, and the catch
method is used to specify a callback function that will be executed if any of the input promises are rejected.
In the example, the input promises are all resolved successfully, so the new promise created by Promise.all
is also resolved. The "then" callback function is executed, and the array of resolved values (1, 2, and 3) is logged to the console.
If any of the input promises are rejected, the new promise created by Promise.all
will be rejected with the value of the first rejected promise. In this case, the "catch" callback function will be executed, and the error value will be passed to the function as an argument.
Here is another example of how to use the Promise.all
method to handle the results of multiple asynchronous operations:
function getUserData(userId) {
return new Promise(function (resolve, reject) {
// perform asynchronous operation to retrieve user data
setTimeout(function () {
let userData = {
id: userId,
name: "Deepak Akin",
age: 26,
occupation: "Developer",
};
resolve(userData);
}, 1000);
});
}
let user1Promise = getUserData(1);
let user2Promise = getUserData(2);
let user3Promise = getUserData(3);
Promise.all([user1Promise, user2Promise, user3Promise])
.then(function (userDataArray) {
userDataArray.forEach(function (userData) {
console.log(userData);
});
})
.catch(function (error) {
console.error(error);
});
Output
{ id: 1, name: 'Deepak Akin', age: 26, occupation: 'Developer' }
{ id: 2, name: 'Deepak Akin', age: 26, occupation: 'Developer' }
{ id: 3, name: 'Deepak Akin', age: 26, occupation: 'Developer' }
In this example, the getUserData
function is used to perform an asynchronous operation to retrieve user data for a given user ID. The Promise.all
method is then used to create a new promise that will be resolved when all of the user data promises (user1Promise, user2Promise, and user3Promise) have been resolved. The then
callback function is used to handle the resolved values, which are an array of user data objects, and the "catch" callback function is used to handle any errors that may occur.
In this example, the input promises are all resolved successfully, so the new promise created by Promise.all
is also resolved. The then
callback function is executed, and the array of user data objects is logged to the console. If any of the input promises are rejected, the new promise created by Promise.all
will be rejected, and the error will be handled by the catch
callback function.
One advantage of using the Promise.all
method is that it allows you to perform multiple asynchronous operations concurrently, and to handle the results of those operations when they are all complete. This can be more efficient than performing the operations sequentially, since it allows you to take advantage of any idle time that may be available while the asynchronous operations are being performed.
Another advantage of using the Promise.all
method is that it allows you to easily handle errors that may occur during the asynchronous operations. If any of the input promises are rejected, the new promise created by Promise.all
will be rejected, and the error can be handled in a single, centralized location using the catch
callback function. This makes it easier to manage errors and to avoid having to handle them individually for each asynchronous operation.
Summary
The Promise.all
method is a useful tool for performing multiple asynchronous operations concurrently, and for handling the results of those operations when they are all complete. By using Promise.all
, you can take advantage of idle time and easily manage errors that may occur during asynchronous operations.
References
Promise.all() - JavaScript | MDN (mozilla.org)