0

I have an issue where I need to wait for a foreach loop to return each time. I tried placing await in some places and tried to use a Promise but I can't get it working. Have a look at the below code to understand my question better.

arr = [1, 2, 3];

MyFunction = async function() {
    arr.forEach(async element => {
        setTimeout(() => {
            console.log(element);
        }, 1000); 
    });
    console.log('done');
}

MyFunction();

With this code you get:

done
1
2
3

How do I use await or something to make it come out:

1
2
3
done
Freddy Bonda
  • 1,189
  • 6
  • 15
  • 33
  • You can't do that with a regular foreach loop, you need to wrap it in a custom recursive function or a similar behavior. – briosheje Sep 27 '18 at 06:46

2 Answers2

2

Check out Promise.all(). Essentially, use .map() on an array to turn it into an array of promises, and then await them all, and then continue execution.

arr = [1, 2, 3];

MyFunction = async function() {
    var promises = arr.map(element => {
        return new Promise((resolve) => {
          setTimeout(() => {
              console.log(element);
              resolve();
          }, 1000); 
        });
    });
    
    await Promise.all(promises);
    console.log('done');
}

MyFunction();
Blue
  • 22,608
  • 7
  • 62
  • 92
0

Using async or await does not magically turn a callback based async function into a Promise based you that you could await. So you need to promisify the callback based asnyc code:

return new Promise(resolve => {
  setTimeout(() => {
    console.log(element);
    resolve()
  }, 1000);
})

The arr.forEach will break the Promise chain as you don't save the Promise created in the arrow function, and as of that you cannot wait for them. So you need to use map, and Promise.all:

arr = [1, 2, 3];

MyFunction = async function() {
  await Promise.all(arr.map(async element => {
    return new Promise(resolve => {
      setTimeout(() => {
        console.log(element);
        resolve()
      }, 1000);
    })
  }));
  console.log('done');
}

MyFunction();

If it is required that the async tasks are done in order then you could use a regular for loop.

arr = [1, 2, 3];

MyFunction = async function() {
  for( let element of arr) {
    await new Promise(resolve => {
      setTimeout(() => {
        console.log(element);
        resolve()
      }, 1000);
    })
  }
  console.log('done');
}

MyFunction();
t.niese
  • 39,256
  • 9
  • 74
  • 101