0

I want to create an array of async functions but I can't understand why it works with map but not with the for loop. Can someone explain the differences between for loop and map in this case?

async function sleep(ms) {
  await new Promise((r) => setTimeout(r, ms));
}

async function logic(i) {
  let time = i * 500;
  await sleep(time);
  console.log(`${i} finished after ${time}`);
  return time;
}

function exampleConstructResultsViaMap(data) {
    const tasks = data.map((date, i) => {
      const task = async() => logic(i);
      return task;
    });
  return tasks;
}

function exampleConstructResultsViaFor(data) {
  const tasks = [];
  let i = 0;
  for (const date of data) {
    const task = async() => logic(i);
    tasks.push(task);
    i++;
  }
  return tasks;
}

(async() => {
  const data = ['a', 'b'];

  const tasksMap = exampleConstructResultsViaMap(data);
  const resultsMap = await Promise.all(tasksMap.map((p) => p()));
  console.log(resultsMap); // [0, 500]

  const tasksFor = exampleConstructResultsViaFor(data);
  const resultsFor = await Promise.all(tasksFor.map((p) => p()));
  console.log(resultsFor); // [1000, 1000]
})();
pushkin
  • 8,468
  • 14
  • 46
  • 86
kfaria
  • 147
  • 1
  • 10
  • 1
    Does this answer your question? [JavaScript closure inside loops – simple practical example](https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – ASDFGerte Jan 10 '20 at 00:15

1 Answers1

2

When you call logic(i) in exampleConstructResultsViaFor the loop has already finished, and i equals 2.

What you can do is use a simple for loop with let that's block scoped:

function exampleConstructResultsViaFor(data) {
  const tasks = [];
  for (let i = 0; i < data.length; i++) {
    const task = async() => logic(i);
    tasks.push(task);
  }
  return tasks;
}

Or create a closure:

const task = ((j) => async() => logic(j))(i);
Marcos Casagrande
  • 33,668
  • 7
  • 72
  • 89
  • So the functions (tasks) have acces to the parent scope (lexical scope). And when invoking the functions they use the i of the outer function scope which is 2 at this point? – kfaria Jan 10 '20 at 10:20
  • Exactly. That's why with a closure you fix that issue, which is why it works with `map`. – Marcos Casagrande Jan 10 '20 at 19:39