Breaking down confusion of combining Async/Await with Array.forEach()
Tags: await, foreach, javascript, synchronous
Published: 2019-11-08 11:38:11

---
title: Breaking down confusion of combining Async/Await with Array.forEach()
published: true
description: Using async/await in popular array methods (Array.forEach(), Array.map() etc.) can be quite confusing. Let's try to break it down and understand what is confusing us.
tags: await, forEach, javascript, synchronous
---

Last week I was having a normal day at work when I suddenly stumbled upon something that really confused me. I was trying to loop an array and call an async function for each element. Yet, the result I was getting was not what I expected.

A dummy version of the situation I had could be:

```javascript
const names = ['George', 'Margie', 'Anna']
const delay = () => new Promise(resolve => setTimeout(resolve, 3000))

names.forEach(async (name) => {
  await delay()
  console.log(`Greetings to you ${name}`)
})

console.log('farewell')
```

By simply running this in `node` we get the following result: 

```
$ node awaitForEach.js

farewell
Greetings to you George
Greetings to you Margie
Greetings to you Anna
```

## What? Wait a second...

That was not what I would expect to see. We definitely have an `await` when we are calling `delay` and `Array.prototype.forEach` is a synchronous function, so I would be quite confident that the greetings should appear before the `farewell` is printed in the console.

## A deep look on `Array.prototype.forEach`

That can get quite very confusing, until you actually take a look at how `Array.prototype.forEach` is implemented. 

A simplified version would be: 

```javascript
Array.prototype.forEach = function(callback, thisArg) {
  const array = this
  thisArg = thisArg || this
  for (let i = 0, l = array.length; i !== l; ++i) {
    callback.call(thisArg, array[i], i, array)
  }
}
```

As you can see, when we are calling the callback function, we are not waiting for it to finish. 
That means, waiting for our `delay()` function to finish is not enough when `Array.forEach()` is not waiting for our callback to finish as well!

## Let's try again

Alright, now we could solve this in many ways. But let's try to fixing the issue in the actual `Array.forEach()`. 

Let's write our own `asyncForEach`!

We just need to make the loop wait for the callback to finish before moving forward to the next element.

```javascript
Array.prototype.asyncForEach = async function(callback, thisArg) {
  thisArg = thisArg || this
  for (let i = 0, l = this.length; i !== l; ++i) {
    await callback.call(thisArg, this[i], i, this)
  }
}

```

Then let's try our previous scenario. Now instead of `Array.prototype.forEach` we are going to use our own `Array.prototype.asyncForEach`.

(Note that we wrapped our code into a `greetPeople()` function, since we now need to `await` for the `asyncForEach()`, which can only be inside an `async` function.)

```javascript
const greetPeople = async (names) => {
  const delay = () => new Promise(resolve => setTimeout(resolve, 3000))

  await names.asyncForEach(async (name) => {
    await delay()
    console.log(`Greetings to you ${name}`)
  })

  console.log('farewell')
}

greetPeople(['George', 'Margie', 'Anna'])
```

And as we all expect, if we now run our updated code the outcome is the one that we desire. 

```
$ node awaitForEach.js

Greetings to you George
Greetings to you Margie
Greetings to you Anna
farewell
``` 

## We made it!

We have our own async-friendly `forEach` array implementation. 
Note that we could have the same behavior with other popular `Array` functions like `Array.map` or `Array.filter`.

Now I have to admit, this is probably not always going to be the best way to solve the issue.
But this is a great way understanding a bit better how `Array.forEach` actually works and in what scenarios it can get a bit problematic/confusing. 


## Meme award section

Well, if you are reading this it means that you actually read the whole thing, wow! 
Your award is this nice corgi picture:

![Awesome corgi loading...](https://cdn.pixabay.com/photo/2019/06/22/14/57/dog-4291714_960_720.jpg)

If you find any mistake do not hesitate to leave a comment.
Any feedback is welcome :)