Asynchronous loops in Javascript - using forEach, map, and for loop
By Anshuman Bhardwaj

Asynchronous loops in Javascript - using forEach, map, and for loop

Asynchronous operations are crucial when working with web applications. We can all agree how easy async/await has made our lives while dealing with asynchronous operations.

In this post, we are going to see how to use loops with async/await.

Before we dive into it, here are the utility functions I used for the demo

// creates a logger function to print logs with function nam
function getLogger(fnName) {
  return function logger(value, diffInMS) {
    return console.log(
      `${fnName}: Item ${value} finished waiting ${Math.round(
        diffInMS / 1000
      )} seconds later.`
    );
  };
}

// simulates an async flow, a network request for example
async function waitFor(seconds) {
  // used to create the fancy waterfall
  fetch("https://random-data- 
         api.com/api/stripe/random_stripe" + Math.random());

  // the fake asynchronous task
  return new Promise((resolve, reject) => {
    setTimeout(resolve, seconds * 1000);
  });
}
        

The classic For loop

const list = [1, 2, 3, 4, 5, 6, 7, 8 , 9, 10];

export async function mainWithFor() {
  const start = Date.now();
  const logger = getLogger("mainWithFor");
  for (const item of list) {
    await waitFor(2);
    const later = Date.now();
    logger(item, later - start);
  }
}        

Runs the code sequentially, one by one. Waiting for each?waitFor?to finish before proceeding to the next iteration.

The image below shows a nice waterfall demonstration, look how each green section starts 2 seconds after the previous one. (don't worry about their duration, as it's a random endpoint. Only for the sake of waterfall depiction)

async for loop waterfall

You'll also notice that the logs appear at a 2-second difference, one by one.

No alt text provided for this image

A good use case for this approach would be to run sequential operations, where you want the next operation to run once the former has finished.

The forEach higher-order method


export async function mainWithForEach() {
  const start = Date.now();
  const logger = getLogger("mainWithForEach");
  list.forEach(async (item) => {
    await waitFor(2);
    const later = Date.now();
    logger(item, later - start);
  });
}
        

The?forEach?loop acts differently than the?for?loop, while the?for?loop?await?the iteration before moving further, the?forEach?loop executes all of the iterations simultaneously. So all the ten executions start at the same point and log after 2 seconds.

No alt text provided for this image

We can also observe the same using a waterfall diagram, look how they all began at the same time. (Again please ignore the duration of each execution, it's random-api).

No alt text provided for this image

A good use case for this approach would be to run parallel operations, where you don't care if the previous one finished or not. It's much faster compared to?for?loop. But there is a caveat to this approach: if the api you're requesting has some sort of rate-limiting setup then making simultaneous requests can backfire.

The map higher-order method

export async function mainWithMap() {
  const start = Date.now();
  const logger = getLogger("mainWithMap");
  const promises = list.map(async (item) => {
    await waitFor(2);
    const later = Date.now();
    logger(item, later - start);
  });
  const finalAnswer = await Promise.all(promises)
}        

The?map?function behaves exactly the same as?forEach?in terms of async operations, meaning all of the callbacks start at the same time and log exactly after 2 seconds.

On top of this, the?.map?returns an array of promises, (one promise per execution, in the same order).

Later we can do an?await Promise.all(promises)?to get the final answer array from it.

map?should be used at places where you would need to return some data based on each async operation. If that's not the case, sticking with?forEach?wouldn't be a bad choice.

Here is the link to?codesandbox, in case you want to try this out yourself.

I have also created a?YouTube video?giving hands-on explanation to this post,

I hope this post was helpful to you. Should you have any feedback or questions, please feel free to ask them in the comments below. I would love to hear and work on them.

Please follow me for more such posts.

Annan Cai

Entry-Level Web Developer | NodeJS, Express, Vue | Seeking Part-Time Opportunities | 2025 Graduate

2 个月

Found out about this the hard way when I spent an hour scratching my head over an issue caused by the parallel execution of forEach. This post sums everything up nicely!

回复
Michael-John Marais

Software Developer

9 个月

thanks very helpful and simple explanation.....

回复
Pankti P.

IT Services: Solutions | Resourcing | Recruitments

1 年

Anshuman, Hi! We, ADFAR Tech require 10 Senior React Native Tech Leads (OFFSHORE). -10+ years of exp. - Banking & finance domain exp. - Team & Tech Lead with end of end project exp. If you wish to partner with us, please WhatsApp. Regards, Pankti | ADFAR Tech +966 59 49 72 620

回复
Mital (Dalia) P.

Information Technology Specialist at ADFAR Tech Ventures

1 年

Anshuman, thanks for sharing! We, ADFAR Tech require 10 Senior React Native Tech Leads (OFFSHORE). -10+ years of exp. - Banking & finance domain exp. - Team & Tech Lead with end of end project exp. If you wish to partner with us, please WhatsApp. Regards, Mital | ADFAR Tech +966 59 49 72 620

回复
Guillaume Theret

Je vous aide à garder l'esprit tranquille pour votre famille et vos biens ????? | Expert Sécurité Verisure | Solutions de sécurité B2B & B2C ?? ??

2 年

Thank you so much for this post. Arrived here Googling my problem and I never thought I'd find my answer on LinkedIn ;)

要查看或添加评论,请登录

社区洞察

其他会员也浏览了