Wait for Multiple Fetch Requests to Finish

OpenJavaScript 0

Last updated: January 14, 2023.

To wait for multiple fetch requests to complete before doing something, first stores all of the requests inside an array.

In the fetch examples below, requests are being made for ficticious posts, comments and photos data from JSONPlaceholder, a free test API for fetching JSON data:

const array = [
  fetch('https://jsonplaceholder.typicode.com/posts'),
  fetch('https://jsonplaceholder.typicode.com/comments'),
  fetch('https://jsonplaceholder.typicode.com/photos')
];

The native Promise object constructor, which can be used to create new promises, also has methods available on it for handling multiple promises.

Since fetch is promise-based, we can use the Promise objects method for handing multiple fetch requests.

To wait until all requests have resolved successfully before doing something, you can use Promise.all(), passing in the array of fetch requests. Handle this like a regular promise and the output will be an array with three response objects.

Because the processing of the response objects with res.json() also returns promises that need to be waited upon, you can use Promise.all() to wait on them as well.

The final output will be an array of three JavaScript object containing the posts, comments and photos data.

Promise.all(array)
.then(responses => {
  return Promise.all(responses.map(response => response.json()))
  .then(data => {
    console.log(data); // Array(3) [ (100) […], (500) […], (5000) […] ]
  })
})
.catch(err => console.error("Multiple fetch failed"))

This solution is functional but involves nested promise-handling.

This can be avoided by creating an async function instead and then using await to wait upon promises to complete:

async function makeRequests() {

  try {

    const responses = await Promise.all(array);
    const data = await Promise.all(responses.map(response => response.json()))
    console.log(data); // Array(3) [ (100) […], (500) […], (5000) […] ]

  } catch {

    console.error("Multiple fetch failed");

  }
}

makeRequests();

One potential issue with this solution is that if one fetch fails, the entire Promise.all() will fail and trigger the catch block in the code below:

const array = [
  fetch('https://jsonplaceholder.typicode.com/posts'),
  Promise.reject(), // Simulates first fetch failing immediately
  fetch('https://jsonplaceholder.typicode.com/photos')
]

async function makeRequests() {
  try {
    const responses = await Promise.all(array);
    const data = await Promise.all(responses.map(response => response.json()))
    console.log(data);
  } catch {
    console.error("Multiple fetch failed"); // Error message logs to console
  }
}

makeRequests();

Avoiding 'fail-fast' behavioir

If you want to avoid the 'fail-fast' of Promise.all() behavior, use Promise.allSettled() instead.

Instead of returning an array of return values, Promise.allSettled() returns an array of objects. Each object has a status property with a value of either 'fulfilled' or 'rejected'.

For promises (e.g. fetch requests) that are successfully fulfilled, a value property also exists on the object containing the return value.

For rejected promises, a reason property exists that may give more information on why the promise failed.

Adapted to the previous example, we can now get the values for fetch requests that succeed, even if one fails:

const array = [
  fetch('https://jsonplaceholder.typicode.com/posts'),
  Promise.reject(), // Simulates first fetch failing immediately
  fetch('https://jsonplaceholder.typicode.com/photos')
]

async function makeRequests() {
  try {
    const responses = await Promise.allSettled(array);
    // Handles array of fetch requests with Promise.allSettled()

    const successArray = [];
    responses.map(response => { 
      if (response.status === "fulfilled") {
        successArray.push(response);
      }
    })
    // Pushes only successfully fulfilled responses into successArray

    const data = await Promise.allSettled(successArray.map(response => response.value.json()))
    // Reads readable stream on body of responses in successArray to JS object (from JSON)

    data.forEach(obj => console.log(obj.value))
    // Logs values on objects (return values of successful fetches)
    // Array(100) [ {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, … ]
    // Array(5000) [ {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, … ]

  } catch {
    console.error("Multiple fetch failed");
  }
}

makeRequests();

Related posts