⚠ Created by AI 🤖

Array.prototype.forEach() doesn’t “respect” async/await because it was never designed to handle promises.

Consider this code:

const items = [1, 2, 3];

items.forEach(async (item) => {
  await new Promise((resolve) => setTimeout(resolve, 1000));
  console.log(item);
});

console.log("done");

Output:

done
1
2
3

Many developers expect:

1
2
3
done

but that’s not what happens.

Why?

forEach simply calls your callback for every element and immediately returns:

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

When the callback is async, it returns a Promise:

async (item) => { ... }

So internally it’s effectively doing:

callback(1); // returns Promise
callback(2); // returns Promise
callback(3); // returns Promise
return; // forEach finishes immediately

forEach:

  • does not collect the promises
  • does not await them
  • does not return a promise itself

Therefore await items.forEach(...) is also useless:

await items.forEach(async (item) => {
  await doSomething(item);
});

because forEach() returns undefined, not a Promise.


Use for...of for sequential async work

for (const item of items) {
  await doSomething(item);
}

This waits for each iteration before moving to the next.


Use Promise.all() for parallel async work

await Promise.all(
  items.map(async (item) => {
    await doSomething(item);
  }),
);

This starts all operations immediately and waits until all finish.


Why wasn’t forEach changed?

Changing its behavior would break existing JavaScript code.

Historically:

  • forEach was added in ES5 (2009).
  • Promises arrived later.
  • async/await arrived much later (ES2017).

By then, millions of programs relied on forEach being synchronous and returning undefined, so JavaScript couldn’t safely redefine it to await promises.

Rule of thumb

  • Need sequential async processing → for...of + await
  • Need parallel async processing → Promise.all(items.map(...))
  • Avoid async callbacks inside forEach unless you intentionally don’t care when they finish.