Promise.all — a helpful tool for async JS

Jeremy Gottfried
Jeremy Gottfried’s tech blog
3 min readSep 17, 2018

Web apps often need to fetch a bunch of data from an API, but not all of that data is accessible from a single endpoint. In those cases, you need to make multiple fetches in order to gather all the necessary data.

This can get messy if you need to make a large number of requests. Suppose you want to load a user’s followers on a social media app, but you are only storing the followers as a list of user ids. You have to make separate fetches to the API endpoint for each follower.

Here’s what that looks like:

const follower_ids = [1, 2, 4, 6, 7, 50, 39, 65] fetch('https://my-api.com/user/1')
fetch('https://my-api.com/user/2')
fetch('https://my-api.com/user/4')
fetch('https://my-api.com/user/6')
fetch('https://my-api.com/user/7')
fetch('https://my-api.com/user/50')
fetch('https://my-api.com/user/39')
fetch('https://my-api.com/user/65')

Normally, you’d have to handle each of the promises separately. The promises would all resolve separately as well, so you’d have no way to predict the order in which the data renders. Then every time you load the webpage, the friends are listed in a different order.

This is where Promise.all comes to the rescue. Promise.all allows you to store a large number of promises in a specific order and then handle them all at once. Here’s what that looks like:

const follower_ids = [1, 2, 4, 6, 7, 50, 39, 65];const promises = follower_ids.map(id => fetch('https://my-api.com/user/' + id)
)
Promise.all(promises)
.then(res => {
const responses = res.map(response => res.json())
return Promise.all(responses)
})
.then(responses => // do something with the responses
)

Let me break down the flow for you so its easy to understand.

1. Create an array of promises

const promises = follower_ids.map(id => fetch('https://my-api.com/user/' + id)
)

In the first line, I create a fetch to each follower’s API endpoint, and I store the fetches in an array called promises .

2. Pass the promises array to Promise.all

Promise.all(promises)

I pass the promises array into Promise.all, which creates a single promise. Promise.all will only resolve when all the fetches inside of it have resolved. Then it will return an array of resolved promises.

3. Convert the responses array to usable data

.then(res => {
const responses = res.map(response => res.json())
return Promise.all(responses)
})

I ask each response in the responses array to return its own json. .json() creates a new promise for each of the responses, so I need to handle that with another Promise.all .

If you are using Promise.all for handling non-json requests, you may need to alter this step. For example, you could use Promise.all to wait for a bunch of setTimeouts to complete.

4. Use the data returned by Promise.all

When the second Promise.all resolves, now you have usable data for every request you made. You can iterate through these requests to render all of the data at once.

One cool use for this is you can render a loading icon that only disappears when all of your data is ready.

Here’s a very simple implementation of everything I have covered:

Enjoy!

--

--