0

I was wondering what is the problem here, why is the return statement not waiting to finish the previous instruction? orders are empty, even though I'm logging inside the getOrders to make sure there were data (there is data).

await stores.forEach(async (store) => {
  let arr = await getOrders(store, token, tokenType);
  orders.push(arr);
})
return orders;

sam
  • 1,767
  • 12
  • 15

2 Answers2

1

To wait for all promises, you need an array of promises, which you can get using map. Then you need to use Promise.all, so that it will wait for all the promises in that array to complete.

const orders = await Promise.all(
  stores.map(store => getOrders(store, token, tokenType))
);
return orders;

*Edit: rewritten and simplified based on suggestion from @PatrickRoberts

To paraphrase his comment, in the old code when using a separate array with an array.push, the array ordering would be indeterminate. However using the array of results from Promise.all will always match the order of the original array.

David784
  • 7,031
  • 2
  • 22
  • 29
  • Thanks for the fast reply! That `Promise.all` means that each iteration is going to wait for the previous to finish? –  Nov 08 '21 at 19:41
  • 1
    No, `Promise.all` allows promises to run in parallel. But `all` won't resolve until all the promises in the collection have resolved. – David784 Nov 08 '21 at 19:43
  • 1
    Thank you, David! I really appreciate your help. I'll accept your answer in a couple of minutes :) –  Nov 08 '21 at 19:46
-1

It's a common misunderstanding that asynchronous callbacks (declared with async and called with await) passed to forEach or map will be executed synchronously or in order. Actually, they are not.

When you check the polyfill of those methods, you'll find a line like this callback.call(T, kValue, k, O);. So, basically, it just execute the callback. If the callback is an asynchronous method, it doesn't wait its execution to be done. Instead, it continue executing other codes.

Let's set an example using your code, let' say this is the callback:

const callback = async (store) => {
  let arr = await getOrders(store, token, tokenType);
  orders.push(arr);
})

When it was passed to forEach:

stores.forEach(callback);

basically, what forEach does is iterating the array, and call callback on each elements. May looks like this

...
loop {
  callback.call(...)
}
...

There is no wait here. However, each time, the code inside your callback is executed synchronously since it's declared with async and called with await, which means after getOrders is resolved and the result is pushed to orders.

So, if you want to execute the callbacks synchronously and in order, you may write a generic for loop.

async function addOrders(){
  for(let store of stores) {
    let arr = await getOrders(store, token, tokenType);
    orders.push(arr);
  }
}

addOrders()

sam
  • 1,767
  • 12
  • 15