2

I wanna execute series of things in the same order for each item i have and collect the information then send statistics at the end.

here is the example code:

let listOfItems = [];
assignedItems.forEach(async (item) => {
    let id = item.myID;
    totalItemCount += await itemRepository.getItemCount(id);

    let itemDetail = await itemRepository.getDetails(id);
    listOfItems.push(item.name);
}, this);
console.log(listOfItems.length); // 0 ??

vs

let listOfItems = [];
for (let i = 0; i < assignedItems.length; i++) {
    let id = assignedItems[i].myID;
    totalItemCount += await itemRepository.getItemCount(id);

    let itemDetail = await itemRepository.getDetails(id);
    listOfItems.push(itemDetail.name);
}
console.log(listOfItems.length); // 5 as expected

output using foreach: 0 (because foreach is executed later) output using for: 5 as expected (because for is executed as code execution is written)

Main issue is: foreach is executed after my console.logs which are written after foreach as i want to collect first all the details for the items and then send the data i have collected.

What the hell is doing on? how do i fix the issue using foreach?

Emrah Mehmedov
  • 1,492
  • 13
  • 28
  • I think your question is a duplicate https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop/37576787 – Mark Odey May 29 '20 at 19:25

1 Answers1

5

.forEach() won't work with await the way you want it to. Just use an actual for loop with await if you want to serialize things.

If you have a problem with not using .forEach(), then please explain that problem so we can help solve that problem.

.forEach() is synchronous and will not await anything and there's no way to change it to do so. You have to loop differently if you want each iteration of the loop to await your promise. The for loop will do that for you in ES6 (that's an explicitly designed feature of ES6) or you can custom code your own manual loop that will await, but .forEach() won't do it.

What the hell is doing on?

.forEach() is synchronous. It doesn't await your promise. That's how it is designed.

how do i fix the issue using foreach?

You don't. Use a regular for loop if you want to await each iteration of the loop before proceeding. This is a feature of ES6 with regular for loops, not with .forEach().


FYI, if you want a .forEach() like feature that will wait for a promise, you can use the Bluebird promise library and use something like Promise.mapSeries() or Promise.each(). Those functions both look for a promise returned from their callback and don't execute the next iteration until those promises are resolved. But, array.forEach() does not have that feature built in.


There are also design patterns using .reduce() and promises for sequencing through an array calling an async operations in series. You can see examples of that pattern in these answers:

how to write to new files sequentially

Can Promise load multi urls in order?

iterating over promises node js

how to make synchronous http calls using promises in node.js

jfriend00
  • 683,504
  • 96
  • 985
  • 979