Tuesday, October 29, 2019

Array.prototype.forEach() function does not await..

Recently I discovered that Array.prototype.forEach() function is not suitable for 'awaitable' functions. Let's have a look at an example.

const getAsyncData = (n) => {
   return new Promise((resolve, reject) => {
      setTimeout(() => resolve(n), 500)
   })
};

const arr = [1,2,3,4,5];

//forEach example
(async () => {
   let total = 0;
   arr.forEach(async n => {
      let res = await getAsyncData(n);
      console.log(res);
      total += res;
   });
  
   console.log('total = ' + total);
})();

I expected that forEach will await for every call of the getAsyncData() function so that to calculate total correctly, but surprisingly the result was different.

total = 0
1
2
3
4
5

Obviously, forEach ignores await keyword and quits immediately so total is not calculated.

To make await working properly I replaced forEach with for .. of

//for of example
(async () => {
   let total = 0;
   for (let n of arr){
      let res = await getAsyncData(n);
      console.log(res);
      total += res;
   }
  
   console.log('total = ' + total);
})();

That approach gives expected result:

1
2
3
4
5
total = 15

Alternatively, we can also use Promise.all function if processing order does not matter

//Promise.all example
(async () => {
   let total = 0;
  
   total = await Promise.all(arr.map(n => getAsyncData(n)))
      .then(results => results.reduce((acc, el) => acc + el));
  
   console.log('total = ' + total);
})();

No comments:

Post a Comment