user12669401
user12669401

Reputation: 249

Wait for the loop to finish before performing the next action

I have the following loop that is fetching data and then store it into the allVegetables variable. I need the loop to finish before I can log the length of the array. With the below code I get zero for the length of allVegetables

var allVegetables = [];

for (var i = 0; i < 10; i++) {

  //fetch the next batches of vegetables
  fetch(`https://www.nofrills.ca/api/category/NFR001001002000/products?pageSize=48&pageNumber=${i}&sort=title-asc`, {
    "headers": {
      ...      
    },
    "referrer": "https://www.nofrills.ca/Food/Fruits-%26-Vegetables/Vegetable/c/NFR001001002000?sort=title-asc",
    "referrerPolicy": "no-referrer-when-downgrade",
    "body": null,
    "method": "GET",
    "mode": "cors"
  }).then(
    function (response) {
      if (response.status !== 200) {
        console.log('Looks like there was a problem. Status Code: ' +
          response.status);
        return;
      }

      response.json().then(function (data) {
        //ad the results of the data to the array
        allVegetables = allVegetables.concat(data.results);
      });
    })
};

console.log("number of vegetables are:", allVegetables.length);

Currently the logs give me zero which I assume it is because it is not waiting for the loop to finish filling up the array allVegetables. I also assume I should use async but I am a newbie and cant figure out how to do this

Upvotes: 0

Views: 578

Answers (2)

Emiel Zuurbier
Emiel Zuurbier

Reputation: 20924

Try to store all the fetch requests, and their results in an array. This will result in an array of promises. With these promises you can wait for all of the to finish with Promise.all and handle the output of all the responses in a single go and store them all in the allVegetables variable.

Because you'll end up with an array of array use Array.prototype.flat() to create a single array with all the values which you can assign to your allVegetables variable.

let allVegetables = [];
let iterations = 10;

const requests = Array(iterations).fill().map((_, i) => fetch(`https://www.nofrills.ca/api/category/NFR001001002000/products?pageSize=48&pageNumber=${i}&sort=title-asc`, {
  "headers": {
    ...      
  },
  "referrer": "https://www.nofrills.ca/Food/Fruits-%26-Vegetables/Vegetable/c/NFR001001002000?sort=title-asc",
  "referrerPolicy": "no-referrer-when-downgrade",
  "body": null,
  "method": "GET",
  "mode": "cors"
}).then(response => {
  if (response.status !== 200) {
    throw new Error('Looks like there was a problem with request ${i}. Status Code: ' + response.status);
  }
  return response.json();
}).then(data => {
  return data.results;
});

const responses = Promise.all(requests).then(data => {
  allVegetables = [...allVegetables, ...data.flat()];
}).catch(error => {
  console.log(error);
});

Upvotes: 1

eloyra
eloyra

Reputation: 529

You could store all your fetch promises inside an array and then use Promise.allSettled to wait for them to finish their work.

Here is a quick example:

const responses = [];
for (let i = 0; i < 4; i++) {
  responses.push(
    fetch("https://jsonplaceholder.typicode.com/posts/1").then(response =>
      response.json()
    )
  );
}
Promise.allSettled(responses).then(console.log);

That will log an array of objects with this shape:

{
  status: 'string',
  value: Object
}

Being the 'value' attribute the one containing the information retrieved from the fetch.

In your case you would simply have to check the length of your array.

You can check the example on a sandbox.

Upvotes: 0

Related Questions