Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save anonimusprogramus/120c651d387a585d56d8617076cc9882 to your computer and use it in GitHub Desktop.

Select an option

Save anonimusprogramus/120c651d387a585d56d8617076cc9882 to your computer and use it in GitHub Desktop.
Do not use forEach with async-await

Array.prototype.forEach can not be used for asynchronous code. (It could not be used with promises, and it can not be used with async-await.)

The following forEach loop might not do what it looks like:

const players = await this.getWinners();

players.forEach(async (player) => {
  await givePrizeToPlayer(player);
});

await sendEmailToAdmin('All prizes awarded');

What's wrong with it?

  • The promises returned by the iterator function are not handled. If one of them throws an error, the error won't be caught.
  • The prizes are awarded in parallel, not serial (one by one).
  • The loop finishes iterating before any of the prizes have been given.
  • As a result, sendEmailToAdmin sends the email before the prizes have been awarded.

So how to do it?

Process each player in serial

for (const player of players) {
  await givePrizeToPlayer(player);
}

Process all the players in parallel

await Promise.all(players.map(async (player) => {
  await givePrizeToPlayer(player);
}));

Process each player in serial, using Array.prototype.reduce

await players.reduce(async (a, player) => {
  await a;
  await givePrizeToPlayer(player);
}, Promise.resolve());

Some people recommend this approach as more "functional" but I find the for-of loop is clearer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment