5

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.

2
  • 1
    You should push the results to data in the Promise.all() code. Commented Mar 12, 2020 at 16:23
  • Thanks @Barmar got it. Commented Mar 12, 2020 at 16:26

2 Answers 2

7

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);
Sign up to request clarification or add additional context in comments.

1 Comment

Damn, I've been stuck on this for hours, can't believe I didn't do that, Thanks.
3

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)
}());

3 Comments

Thanks, this is really great since my data is already in an array
You can also create the array of urls in one-line and full logic can be implemented in few lines.
Thanks, the shorter the better I guess.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.