Responding to Multiple Promises
Up to this point, each example in this chapter has dealt with responding to one promise at a time. Sometimes, however, you’ll want to monitor the progress of multiple promises in order to determine the next action. ECMAScript 6 provides two methods that monitor multiple promises: Promise.all()
and Promise.race()
.
The Promise.all() Method
The Promise.all()
method accepts a single argument, which is an iterable (such as an array) of promises to monitor, and returns a promise that is resolved only when every promise in the iterable is resolved. The returned promise is fulfilled when every promise in the iterable is fulfilled, as in this example:
let p1 = new Promise(function(resolve, reject) {
resolve(42);
});
let p2 = new Promise(function(resolve, reject) {
resolve(43);
});
let p3 = new Promise(function(resolve, reject) {
resolve(44);
});
let p4 = Promise.all([p1, p2, p3]);
p4.then(function(value) {
console.log(Array.isArray(value)); // true
console.log(value[0]); // 42
console.log(value[1]); // 43
console.log(value[2]); // 44
});
Each promise here resolves with a number. The call to Promise.all()
creates promise p4
, which is ultimately fulfilled when promises p1
, p2
, and p3
are fulfilled. The result passed to the fulfillment handler for p4
is an array containing each resolved value: 42, 43, and 44. The values are stored in the order the promises were passed to Promise.all
, so you can match promise results to the promises that resolved to them.
If any promise passed to Promise.all()
is rejected, the returned promise is immediately rejected without waiting for the other promises to complete:
let p1 = new Promise(function(resolve, reject) {
resolve(42);
});
let p2 = new Promise(function(resolve, reject) {
reject(43);
});
let p3 = new Promise(function(resolve, reject) {
resolve(44);
});
let p4 = Promise.all([p1, p2, p3]);
p4.catch(function(value) {
console.log(Array.isArray(value)) // false
console.log(value); // 43
});
In this example, p2
is rejected with a value of 43. The rejection handler for p4
is called immediately without waiting for p1
or p3
to finish executing (They do still finish executing; p4
just doesn’t wait.)
The rejection handler always receives a single value rather than an array, and the value is the rejection value from the promise that was rejected. In this case, the rejection handler is passed 43 to reflect the rejection from p2
.
The Promise.race() Method
The Promise.race()
method provides a slightly different take on monitoring multiple promises. This method also accepts an iterable of promises to monitor and returns a promise, but the returned promise is settled as soon as the first promise is settled. Instead of waiting for all promises to be fulfilled like the Promise.all()
method, the Promise.race()
method returns an appropriate promise as soon as any promise in the array is fulfilled. For example:
let p1 = Promise.resolve(42);
let p2 = new Promise(function(resolve, reject) {
resolve(43);
});
let p3 = new Promise(function(resolve, reject) {
resolve(44);
});
let p4 = Promise.race([p1, p2, p3]);
p4.then(function(value) {
console.log(value); // 42
});
In this code, p1
is created as a fulfilled promise while the others schedule jobs. The fulfillment handler for p4
is then called with the value of 42 and ignores the other promises. The promises passed to Promise.race()
are truly in a race to see which is settled first. If the first promise to settle is fulfilled, then the returned promise is fulfilled; if the first promise to settle is rejected, then the returned promise is rejected. Here’s an example with a rejection:
let p1 = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(42);
}, 100);
});
let p2 = new Promise(function(resolve, reject) {
reject(43);
});
let p3 = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(44);
}, 50);
});
let p4 = Promise.race([p1, p2, p3]);
p4.catch(function(value) {
console.log(value); // 43
});
Here, both p1
and p3
use setTimeout()
(available in both Node.js and web browsers) to delay promise fulfillment. The result is that p4
is rejected because p2
is rejected before either p1
or p3
is resolved. Even though p1
and p3
are eventually fulfilled, those results are ignored because they occur after p2
is rejected.