1

I have a following code which creates remote folders locally if they do not exist:

await remoteFolders
  .filter(rf => !localFolders.some(lf => lf === rf))
  .forEach(async (rf) => await this.createFolder(rf));

Method createFolder looks like this:

async createFolder(folderPath) {
  if (!(await fs.exists(folderPath))) {
    await fs.mkdir(folderPath);
  }
}

The problem is that if I debug I can see that await in forEach is ignored and the loop does not wait until createFolder method finishes. So if I create directories which depend on previous ones, it obviously fails.

But if I use for-loop it works fine (await is taken into account and loop execution continues after createFolder finishes):

for (let i = 0; i < remoteFolders.length; i++) {
  if (!localFolders.some(lf => lf === remoteFolders[i])) {
    await this.createFolder(remoteFolders[i]);
  }
}

I can use this one, but using forEach looks more elegant to me. Why does not forEach take await into account?

Liam
  • 27,717
  • 28
  • 128
  • 190
michal.jakubeczy
  • 8,221
  • 1
  • 59
  • 63

2 Answers2

2

An async function runs until it hits an await, and then returns a promise. ForEach doesn't do anything special when you return a promise. All it sees is that your function returned, and therefore it can move on to the next element of the array. So forEach synchronously steps through the array, calls a bunch of functions, and gets a bunch of promises back which it ignores. Later, the promises will start resolving and your functions will resume running, but this is after forEach has finished.

Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98
0

When using forEach, we specify a callback function. This callback will be executed on each element in the array. When await is used it returns a promise and nothing else. The loop continues and promise is resolved later.

Shyam Kumar
  • 148
  • 9