Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fetch in loop, keep result order

I have a situation where I need to loop through an array of URLs and fetch the result, but I need to preserve the order of requests, that is the first request should be "saved" (write to a file) first, and so on. The result from the requests are text files and their content do not have any data that reveals the original URL or order.

I have made a demo below, which fetches dummy JSON data.

let promises = [];
let data = [];
let i = 1;

let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');

const fn = async() => {
  while (i < 5) {
    promises.push(
      fetch('https://reqres.in/api/users/' + i, {
        mode: 'cors',
        headers: headers
      })
      .then(response => response.json())
      .then(json => {
        data.push(json)
      })
    )
    i++;
  }

  await Promise.all(promises).then(() => {
    console.log(data);
  })
}

fn();

If you test the above code, you can see that the results are in random order (based on id), and since the files in my original code are text files, I can't sort it after fetch.

like image 733
Akshay Avatar asked Mar 12 '20 16:03

Akshay


2 Answers

Use the values the promises resolve to. No need to keep a separate data array and manually add the values to it. Promise.all makes sure the values are in the same order as the promises.

let promises = [];
let i = 1;

let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');

const fn = async() => {
  while (i < 5) {
    promises.push(
      fetch('https://reqres.in/api/users/' + i, {
        mode: 'cors',
        headers: headers
      })
      .then(response => response.json())
    )
    i++;
  }

  await Promise.all(promises).then(data => {
    console.log(data);
  })
}

fn();

And since you are in an async function you can just do:

var data = await Promise.all(promises);
console.log(data);
like image 184
Felix Kling Avatar answered Oct 25 '22 13:10

Felix Kling


Also, you can call this way by creating an array of urls and then calling Promise.all which maps through those urls and returns a single promise with all responses in an array:

let headers = new Headers({'Content-Type':'application/json','Accept':'application/json'});
let params = { mode: 'cors', headers};

(async function() {  
  // Create an array or urls
  const urls = [...Array(4).keys()].map(i => `https://reqres.in/api/users/${i+1}`);
  const response = await Promise.all(urls.map(url => fetch(url, params)))
  const data = await Promise.all(response.map(res => res.json()))
  console.log(data)
}());
like image 24
palaѕн Avatar answered Oct 25 '22 13:10

palaѕн