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
  • 9,575
  • 15
  • 51
  • 95
kfaria
  • 307
  • 2
  • 13
  • 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
  • 37,983
  • 8
  • 84
  • 98
  • 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