how to fix unordered "fetch" in javascript

Viewed 283

I am fetching multiple route using for loop and saving its result this is my code

 for (let i = 0; i < datesToFetch.length; i++) {


fetch("http://localhost:3000/areaChart/"+datesToFetch[i]+"/"+datesToFetch[i+1])
.then(response => response.json())
.then(response => console.log(response))

}

whats really weird that order of data that I am getting is coming random order it is not coming according to for loop ascending order which is really important in this case

what should I do so I get data in proper order ?

4 Answers

What's going on, and how to fix it:

Your code is queueing up a bunch of fetches, but not waiting for them to finish before moving on to the next iteration of the loop. They can finish in any order.

If instead you wanted the loop to stop and wait each time, wrap it in an async function, and await the fetch.

async function test() {

    for (let i = 0; i < datesToFetch.length; i++) {
        var response = await fetch("http://localhost:3000/areaChart/"+datesToFetch[i]+"/"+datesToFetch[i+1]);
        var responseJson = await response.json();
        console.log(responseJson);
    }

}

A simulation of your code:

const delay = t => new Promise(resolve => setTimeout(resolve, t));

async function test() {
  for (let i = 1; i <= 5; i++) {
    console.log(`Starting call #${i}`);
    delay(5000 - (i * 1000))
      .then(() => console.log(`Call #${i} has completed.`));
  }
}

test();

A simulation of the solution provided above:

const delay = t => new Promise(resolve => setTimeout(resolve, t));

async function test() {
  for (let i = 1; i <= 5; i++) {
    console.log(`Starting call #${i}`);
    await delay(5000 - (i * 1000));
    console.log(`Call #${i} has completed.`);
  }
}

test();

Welcome to asynchronous code!

One thing you can do is create an empty array that is datesToFetch.length long, and assign the value of response.json() to the appropriate index.

const responses = [...Array(datesToFetch.length)]

for (let i = 0; i < datesToFetch.length; i++) {
  fetch("http://localhost:3000/areaChart/"+datesToFetch[i]+"/"+datesToFetch[i])
    .then(response => response.json())
    .then(response => responses[i] = response)
}

Your case :

You are calling multiple functions that have different resolution time. It's like behing at mcDonald in different queues, some gyus arrived at the same time as you could get his meal before or after yourself.

function getRandomInt(max) {
  return Math.floor(Math.random() * Math.floor(max));
}

function display(i) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(i);
    }, getRandomInt(1500));
  });
}

for (let i = 0; i < 5; i += 1) {
  display(i)
    .then(x => console.log('->', x));
}


One soluce :

We are using a function called Promise.all to wait for all people to get theirs meals, and then go out of the shop.

function getRandomInt(max) {
  return Math.floor(Math.random() * Math.floor(max));
}

function display(i) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(i);
    }, getRandomInt(1500));
  });
}

const promises = [];

for (let i = 0; i < 5; i += 1) {
  promises.push(display(i));
}

// We use Promise.all to wait for all responses
// The responses are in the call order
Promise.all(promises)
  .then((rets) => {
      rets.forEach(x => console.log('->', x));
  });

That's because this fetch call will be added to the JavaScript event loop. The first one which gives back result will be displayed, so the order can be different then the order in which they are called.

To fix this you should take a look at the await operator. More info can be found here: https://dev.to/johnpaulada/synchronous-fetch-with-asyncawait

Related