DEV Community

loading...

Awaiting multiple requests to finish using Promise.all

Corey Cleary
Tech Lead primarily working with JavaScript and Node.js
Originally published at coreycleary.me ・3 min read

Originally published at coreycleary.me. This is a cross-post from my content blog. I publish new content every week or two, and you can sign up to my newsletter if you'd like to receive my articles directly to your inbox! I also regularly send cheatsheets and other freebies.

The scenario: you want to make multiple requests at the same time, and wait for them all to finish before returning all the data. Or, alternatively, you don't need to return any data but instead just need them all to execute before the function returns.

Maybe you're looking to batch similar requests into X number at a time.

Or maybe you need to wait for the requests to finish before returning a webpage or response.

Instead of having to do something like:

const response1 = await apiRequest()
const response2 = await apiRequest()
const response3 = await databaseRequest()

return [response1, response2, response3]

Or something like this, where you're looping:

const responses = []

for (let i = 0; i < 50; i++) {
  const data = await apiRequest()
  responses.push(data)
}

...there is a much easier way to handle executing those async functions.

Having to wait for each request to finish before making the next one is a pain... and if your use case is such that it doesn't matter what order they run in, no use in taking the performance hit.

Promise.all() to the rescue!

Promise.all is the native function that will solve this problem for us.

It allows us to pass in an array of Promise/async functions and it will wait for each of them to finish before returning.

So whenever you have async functions that need to be executed together and you need to wait for all of them to finish, use Promise.all.

For example, imagine you're building a user profile portion of a dashboard application. And you need to make several HTTP requests and a database request to fetch the data for the user. But it needs to be returned together.

Let's see what that looks like in code...

const userProfileData = await Promise.all([
  getSettings(user)
  getMetadata(user)
  getDefaultLayoutConfig()
])

// destructured example
const [settings, metadata, defaultConfig] = await Promise.all([
  getSettings(user)
  getMetadata(user)
  getDefaultLayoutConfig()
])

Another benefit of using Promise.all is that it will kickoff the functions at the same time - concurrently - as opposed to starting one, waiting for it to finish, then starting the next one. Read more about that here.

Error handling

A quick note on what happens if one of the Promise/async functions fails when using Promise.all - it uses a "fail-fast" approach, so the first function to fail will cause the rest of the functions to not be executed.

Instead, Promise.all will exit early. And it will return a rejected Promise.

There are ways to handle this differently, using .catch() but I'm keeping this post limited to the topic of making multiple requests. I'll talk about the different ways of error handling Promise.all in a future post.

Wrapping up

So, next time you have a scenario in which you have a related set of data you need to asynchronously request and return - and those functions don't depend on each other, they can be executed at the same time - use Promise.all!

Love JavaScript but still getting tripped up by architecture stuff and how you should structure your service? I publish articles on JavaScript and Node every 1-2 weeks, so if you want to receive all new articles directly to your inbox, here's that link again to subscribe to my newsletter!

Discussion (1)

Collapse
oligospermia profile image
Mesalazine

I understand this is clearly a blog promotion ad post, but still would make more sense to list neighboring methods that can achieve different goals in one's project:

  • .allSettled() - returns a promise that resolves after all of the given promises have either resolved or rejected, with an array of objects that each describes the outcome of each promise.
  • .any() - takes an iterable of Promise objects and, as soon as one of the promises in the iterable fulfills, returns a single promise that resolves with the value from that promise. (experimental method)
  • .race() - method returns a promise that fulfills or rejects as soon as one of the promises in an iterable fulfills or rejects, with the value or reason from that promise.