Several promises at once
You often need to run several asynchronous actions at the same time: load a profile and a list of orders, query three servers. For this, the Promise object has static methods that take an array of promises and return one combined promise. They are called combinators.
Every example in this lesson uses a small wait() function: it returns a promise that is fulfilled with value after ms milliseconds.
Promise.all
Promise.all() waits until all the promises are fulfilled and gives an array of results in the same order as the promises:
const wait = (value, ms) => new Promise((resolve) => setTimeout(() => resolve(value), ms));
Promise.all([wait('a', 300), wait('b', 100)]).then((values) => {
console.log(values.join(', ')); // a, b
});Both waits run at the same time, so the whole thing takes 300 ms, not 400.
If one promise fails
If even one promise is rejected, Promise.all() is rejected straight away with its error, and the other results are lost:
const wait = (value, ms) => new Promise((resolve) => setTimeout(() => resolve(value), ms));
Promise.all([wait(1, 100), Promise.reject(new Error('Request 2 failed')), wait(3, 200)])
.then((values) => console.log(values.join(', ')))
.catch((error) => console.log(error.message)); // Request 2 failedThis is handy when there is no point in continuing without any one of the results.
Promise.allSettled
Promise.allSettled() waits for all promises, even rejected ones. Each result is an object with a status field: 'fulfilled' with a value, or 'rejected' with an error in reason:
Promise.allSettled([Promise.resolve(10), Promise.reject(new Error('No connection'))]).then((results) => {
for (const result of results) {
console.log(result.status);
}
});
// fulfilled
// rejectedUse it when you want to show everything that loaded and, separately, what did not.
Promise.race
Promise.race() settles together with the first promise to settle — whether it succeeded or failed. This is how a time limit is made:
const wait = (value, ms) => new Promise((resolve) => setTimeout(() => resolve(value), ms));
const timeout = (ms) => new Promise((resolve, reject) => setTimeout(() => reject(new Error('Time is up')), ms));
Promise.race([wait('Server response', 500), timeout(200)])
.then((value) => console.log(value))
.catch((error) => console.log(error.message)); // Time is upPromise.any
Promise.any() waits for the first successful promise and ignores errors. It is rejected only if all of them fail:
const wait = (value, ms) => new Promise((resolve) => setTimeout(() => resolve(value), ms));
Promise.any([Promise.reject(new Error('Server 1 is down')), wait('Server 2', 300), wait('Server 3', 100)])
.then((value) => console.log(value)); // Server 3| Method | Fulfilled when | Rejected when |
|---|---|---|
Promise.all() | All succeed | The first error |
Promise.allSettled() | All have settled | Never |
Promise.race() | The first to settle succeeded | The first to settle failed |
Promise.any() | The first success | All failed |
Common mistake
Passing the promises as separate arguments instead of an array. Promise.all(first, second) waits for neither of them and is rejected straight away with a TypeError:
const first = Promise.resolve(1);
const second = Promise.resolve(2);
Promise.all(first, second).catch((error) => console.log(error.name)); // TypeErrorThe correct form uses square brackets: Promise.all([first, second]).