The Promise.all()
method in Javascript is a function that accepts many promises and then does something only after they have all been settled. From all the promises you enter into it, it creates a new promise which then waits for each promise to finish, before continuing. That ultimately means you can wait for multiple things to finish before you fire something else.
This method is particularly useful for UI development - for example, if you want a loading symbol to show on the screen until multiple promises conclude, then Promise.all()
provides an easy way to do that. Let's look at how it works.
Promise.all()
accepts an iterable of promises. All that means is it can accept anything that could be iterated over - like an array. You can't put objects or single promises in it.
Let's look at a simple example that utilises timeouts:
let myPromise = () => {
return new Promise((resolve) => {
setTimeout(function() {
resolve('firstPromise')
}, 500)
})
}
let mySecondPromise = () => {
return new Promise((resolve) => {
setTimeout(function() {
resolve('secondPromise')
}, 800)
})
}
Here we have two timeouts, the longest of which takes 800ms. We want the console log the values of each after both are finished.
The easiest way to do this is with Promise.all()
:
Promise.all([ myPromise(), mySecondPromise() ]).then((data) => {
console.log(data) // Console logs [ 'firstPromise', 'secondPromise' ]
})
As you can see, Promise.all()
is tenable, and the data returned is an array of the result from each promise. So, since we passed in myPromise, mySecondPromise
, we get the data of each in an array, in the same order.
While it might be tempting to use await
like so:
let myPromiseFinish = await myPromise()
let mySecondPromiseFinish = await mySecondPromise()
console.log([ myPromiseFinish, mySecondPromiseFinish ])
This is actually less efficient. await
causes both functions to run one after another. That means that by using await
, the total time taken to finish both promises will be 1300ms
.
Promise.all()
lets you run both promises concurrently, meaning that the total operation can take around 800ms
- this is quite useful to know if you are looking to optimize your code.
Since Promise.all()
will return an array of results, and also creates a new promise, we can use await
with Promise.all()
, and capture its output like so:
let [ myPromiseResult, mySecondPromiseResult ] = await Promise.all([ myPromise(), mySecondPromise() ])
Now both of the results of our promises are available once Promise.all()
finishes processing both. Pretty cool, right?
It's important to note that if your promise fires reject
instead of resolve
, Promise.all()
will immediately reject
too. If you are unfamiliar with promise rejections, then that’s the best time to use the reject
function instead of the resolve
function.
Below, the promise will always reject and throw an error Uncaught firstPromise
:
let myPromise = () => {
return new Promise((resolve, reject) => {
setTimeout(function() {
reject('firstPromise')
}, 500)
})
}
So, if a promise in your Promise.all()
set rejects, be sure to anticipate that Promise.all()
will also reject.
Promise.all()
is a really useful way to simplify your code, and also speed it up in some instances - by letting you do promises concurrently. If you're new to Javascript, learning about how promises and async functions work in Javascript is tricky, so I wrote another guide on that - you can learn more about promises here.
Also published here.