-2

I am attempting to use fetch inside a loop (something like the pseudo code below) and I know that the responses may come back in a different order to that in which they were asked. That would be fine so long as I know what the value of ctr was when the fetch request was originally made but I can not fathom a way of getting that information passed from the original fetch call to the processing of the response.

All the example snippets I see about using fetch in loops seem to suggest that you add commands to wait for each fetch call to finish before doing the next one but I presume this would be slower (correct me if you think I'm wrong in that regard).

for (let ctr = 0;ctr < 10;ctr++)
{
    fetch(URL_OF_SOME_API,fetch_options)
    .then((response) => response.json())
    .then(function (data_returned_by_API)
    {
        // do something with data_returned_by_API and ctr
    });
}
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Mick
  • 8,284
  • 22
  • 81
  • 173
  • 2
    You have access to `ctr` inside the `.then` callback. – Unmitigated Mar 27 '23 at 22:54
  • would that be the ctr as it was at the time of the original fetch? – Mick Mar 27 '23 at 22:55
  • 1
    Yes, it will be. – Unmitigated Mar 27 '23 at 23:00
  • This question got marked as a duplicate of a previous question but I noticed the old question was asked nearly 14 years ago and has 44 answers! and the top answer has a highly upvoted comment "Unfortunately, this answer is outdated and nobody will see the correct answer at the bottom". There is also a highly upvoted comment saying "In ES6, a trivial solution is to declare the variable i with let". What's more, if someone is not familiar with the concept of "closure" (and I wasn't) then they will have a hard time finding that other question. Maybe it is time for a fresh question and answer? – Mick Mar 28 '23 at 12:18

2 Answers2

1

Your code already works as intended because of how let works when its variable is used in closures.

const sleep = (ms) =>
  new Promise((resolve) => setTimeout(() => resolve(ms), ms));


for (let ctr = 0; ctr < 10; ctr++) {
  sleep(Math.random() * 5000 + 1000)
    .then(function(data_returned_by_API) {
      console.log(ctr, data_returned_by_API);
    });
}

var doesn't work

const sleep = (ms) =>
  new Promise((resolve) => setTimeout(() => resolve(ms), ms));


for (var ctr = 0; ctr < 10; ctr++) {
  sleep(Math.random() * 5000 + 1000)
    .then(function(data_returned_by_API) {
      console.log(ctr, data_returned_by_API);
    });
}

For more information, you can check out What is the difference between "let" and "var"?

Samathingamajig
  • 11,839
  • 3
  • 12
  • 34
0

You can wrap the internal of the loop inside of an IIFE passing in ctr as an argument, e.g.:

for (let ctr = 0; ctr < 10; ctr++)
{
    ((ctr) => {
        setTimeout(() => { console.log({ctr}) }, Math.random() * 1000)
    })(ctr);
}

Or, you can use Promise.all, like this:

let i = 0;
let p = () => new Promise((resolve) => {
    let j = i++;
    setTimeout(() => { resolve(j); }, Math.random() * 1000);
})


let promises = [];
for (let ctr = 0;ctr < 10;ctr++)
{
    promises.push(p())
}

Promise.all(promises).then((res) => console.log(res));
dave
  • 62,300
  • 5
  • 72
  • 93