forEach loop fails in a promise or async function#

If you haven't faced the issue of async-await not working when used within a forEach loop in an async function or a promise block, you might be shocked to learn that the following code will not work as expected.

Click on the "Run" button to see it.

Run
Clear

It prints an empty string, instead of apple.

Why is this happening? Could there be a non-compliant syntax for promise or async-await code? Let's check.

  • Enclosing main function must be an async function ✅
  • Callback function of forEach must be an async function ✅
  • The result of the async function join must be awaited ✅

Everything looks good. Then why does the code not work as expected?

The problem is in the implementation of forEach. Here is a very simplified representation of of the implementation of forEach.

Array.prototype.forEach = function (callback) {
  for (let i = 0; i < this.length; i++) {
    callback(this[i], i, this);
  }
};

As you can see, callback() is not being awaited. Therefore, the promise chain is broken, resulting in the unexpected behavior.

forEach was implemented way before the concept of promise or async-await was introduced in JavaScript, so, it not working with promise or async-await is not a bug. It is just a case of you using incompatible constructs.

Solution#

Don't use forEach loop in a promise or async function. Instead, use a for loop to iterate through the items of the array.

Run the code below to confirm the solution actually works.

Run
Clear

Summary#

The implementation of forEach loop is not compatible with promise and async functions. Use a for loop to work around this limitation.

References#

  1. MDN - Array.prototype.forEach()
  2. MDN - Promise
  3. MDN - async function