DEV Community

Cover image for How to use async/await inside loops in JavaScript

How to use async/await inside loops in JavaScript

Shadid Haque on October 02, 2021

Iterating through items and dealing with asynchronous logic (i.e. API calls) are probably two of the most common tasks we have to perform as JavaSc...
Collapse
 
dylanwatsonsoftware profile image
Dylan Watson

I think in practice, I'd be horrified if someone tried to use a reduce over a simple for..of for such a simple case but it was a good article. Thanks!

Collapse
 
twelve profile image
nntwelve

Hello @dylanwatsonsoftware , I'm new with JS. I'm really curious about why you horrified, may you give me the best solution for this simple case? Thanks!!

Collapse
 
dylanwatsonsoftware profile image
Dylan Watson • Edited

Hmm just rereading the article. The example I was referring to is:

let result = [3000,2000,1000, 4000].reduce( (accumulatorPromise, nextID) => {
  return accumulatorPromise.then(() => {
    return testPromise(nextID);
  });
}, Promise.resolve());
Enter fullscreen mode Exit fullscreen mode

But you could write it much more simply, something like:

for(let nextID of [3000,2000,1000, 4000]) {
  await testPromise(nextID)
}
Enter fullscreen mode Exit fullscreen mode

Some cases you might need the first one... But usually the 2nd one is much easier to read, which means it's less likely to contain a bug.

Thread Thread
 
twelve profile image
nntwelve

Thank you, the 2nd is easy for me to understand, actually it took me a while to understand why the first one can run.

Collapse
 
mohammedalnuaimi profile image
Mohammed Al-Nuaimi

don't think reduce is a neat way,I found it difficult to read as well, async generator is neat though

Collapse
 
z2lai profile image
z2lai • Edited

Excellent topic and article! The code examples were very clear.

The reduce example is neat, after I re-read a few times to understand it. I think it's unnecessary syntactic sugar for building the .then() chain imperatively using a for loop as others have mentioned. I could be wrong and maybe this pattern of building a .then() chain with reduce is common in practice. But I still think it's better to be simple than smart, even if it means more lines of code. IMO, a reduce is better suited for more trivial problems like calculating a sum.

As for resolving promises in parallel, there is a simple improvement you can make to your code that will get you the contents in the right order to be printed to your console. All you need is to create a new outputArray and a counter=0 variable outside of your iteration, and as you are iterating through the fileNames, pass in the array index of the fileName, and push each promise result into the outputArray using the same index to build outputArray in the same order as the input array. Also within each promise, increment the counter variable and check for when counter=fileNames.length to know when all your promises have resolved before and when you can call console.log(outputArray).

Collapse
 
shadid12 profile image
Shadid Haque

Thank you @z2lai interesting point. I will make a follow up post on this one

Collapse
 
z2lai profile image
z2lai • Edited

I forgot to mention that using a counter variable in my example to determine when all promises have been resolved is actually a replacement for Promise.all() (it might even be that this is how Promise.all() is implemented under the hood).

This approach is very well explained in YDKJS's section on "Interaction" in the Asynchrony chapter. I recommend people to go through that entire section: github.com/getify/You-Dont-Know-JS...

Collapse
 
ijsucceed profile image
Jeremy Ikwuje

This is a great blog post. Your suggestions just save my project more bandwidth. We have a particular endpoint that update the exchange rates of multiple currency pairs, previously this endpoint takes about 30s to complete, now 3s.

Thanks, you deserve some Satoshi!

Collapse
 
yathink3 profile image
yathink3

i think best way to achieve this making prototype function and then good to go

Array.prototype.forAsyncSerial = async function (fn = null) {
let result = [];
for (let i = 0; i < this.length; i++) {
if (typeof fn !== 'function') result[i] = await this[i];
else result[i] = await fn(this[i], i);
}
return result;
};

Array.prototype.forAsyncParallel = async function (fn = null) {
if (typeof fn !== 'function') return await Promise.all(this);
else return await Promise.all(this.map(fn));
};

Collapse
 
saroj8455 profile image
Saroj Padhan

Thank you