Is JavaScript forEach async?

Is JavaScript forEach async?

In this post you will find out the answer to the question of is JavaScript forEach async, or not what the alternatives are, and how you can use them all with examples.

Will Mayger

A post by Will Mayger
September 08, 2021

There is some confusion around using async/await with a JavaScript forEach loop, and whether or not it is asynchronous, what the alternatives are and how to use them.

In this post we will cover everything you need to know about asynchronous looping and answer the question of is JavaScript forEach async, and if not what alternatives you have.

Is JavaScript forEach async?

No. The JavaScript Array.prototype.forEach loop is not asynchronous. The Array.prototype.forEach method accepts a callback as an argument which can be an asynchronous function, but the forEach method will not wait for any promises to be resolved before moving onto the next iteration.

If you need to wait for iterations to complete and finish, then you will be better off using a for loop, which will be explained later on in this post.

The confusion comes from where it is possible to still pass in asynchronous functions that can perform asynchronous actions because the forEach loop accepts a callback as an argument.

The reason why the forEach loop itself is not async is because it will not wait for these functions to resolve (return with the value after the async operation has been finished).

What this means is that whilst you can pass an asynchronous function as the callback, the actual forEach loop will not wait for your function because it does not consider it as asynchronous and just thinks of it as a normal function.

Here is an example of this issue when using async/await with a forEach loop:

const delay = async (ms = 1000) =>
  new Promise(resolve => setTimeout(resolve, ms))

[1, 2, 3].forEach(async num => {
  await delay()
  console.log(num)
})
// after 1 second
// 1
// 2
// 3
Behaviour of async function in non async forEach

As you can see in this example the behaviour is not as you might have expected.

Instead of there being a delay between each iteration, there appears to be a single delay and then all the functions happen at the same time.

There are still the same amount of delays happening but they all start at the same time and end at the same time because the forEach loop does not wait for async callbacks.

To emulate the expected behaviour you would have to modify the delay function by factoring this in.

You could use the array index as a multiplier so even though all the array item delays get triggered at the same time, they will all have different lengths of delays based on the index.

Here is an example of this:

const delay = async (ms = 1000) =>
  new Promise(resolve => setTimeout(resolve, ms))

[1, 2, 3].forEach(async (num, index) => {
  await delay(index * 1000)
  console.log(num)
})
// 1
// 1 second later
// 2
// 1 second later
// 3
javascript foreach async

However this only works in the above example because we can control the delay, this won’t work if you are instead making an async request because it can complete at any point which is outside of our control.

If you still need to create an async loop in JavaScript there are other options that you can use such as a for loop or map instead of the JavaScript Array.prototype.forEach method.

How to create a JavaScript async for loop

One of the best alternatives to create an asynchronous loop is to use a JavaScript for loop.

It can be used in the same way as you ordinarily would write your async code, so all you have to do is ensure that you are writing your async code within an async function and it will work.

Using the above example, let’s create another example but this time of how to create a JavaScript async for loop:

(async () => {
  const delay = async (ms = 1000) =>
    new Promise(resolve => setTimeout(resolve, ms))

  const myArray = [1, 2, 3]

  for (let i = 0; i < myArray.length; i += 1) {
    await delay()
    console.log(myArray[i])
  }
})()
// 1
// 1 second later
// 2
// 1 second later
// 3
javascript async for loop

As you can see by using a for loop it works in the way in which we would expect by waiting for each iteration to complete before moving onto the next.

It is important to remember that this code is working because we have wrapped everything in an async IIFE(Immediately invoked function expression) which is just a way of saying that it is wrapped in an async function that gets called immediately.

The async function wrapper is needed to allow the use of async code.

Summary

There we have is JavaScript forEach async, if you want more like this be sure to check out some of my other posts!

I hope this post has helped, but before you go I highly recommend that you checkout Pluralsight if you are interested in improving your software engineering skills, such as React, JavaScript, or Typescript (and much more).

Not only does Pluralsight provide you with all the learning material you need but it also let's you learn in a fun, interactive way and gives you the ability to see your current progress and level in a certain skill via their Skill Assessment tool which can help you see what you need to learn next to keep improving!

Some graphics used on this post were made using icons from flaticon.