Signup/Sign In
Ask Question
Not satisfied by the Answer? Still looking for a better solution?

Using async/await with a forEach loop

Are there any issues with utilizing async/await in a forEach loop? I'm attempting to loop through an array of files and anticipate the content of each file.
import fs from 'fs-promise'

async function printFiles () {
const files = await getFilePaths() // Assume this works fine

files.forEach(async (file) => {
const contents = await fs.readFile(file, 'utf8')
console.log(contents)
})
}

printFiles()

This code does work, however, could something turn out badly with this? I had somebody reveal to me that shouldn't utilize async/await in a higher-order function like this, so I simply needed to inquire as to whether there was an issue with this.
by

3 Answers

akshay1995
Instead of Promise.all in conjunction with Array.prototype.map (which does not guarantee the order in which the Promises are resolved), I use Array.prototype.reduce, starting with a resolved Promise:

async function printFiles () {
const files = await getFilePaths();

await files.reduce(async (promise, file) => {
// This line will wait for the last async function to finish.
// The first iteration uses an already resolved Promise
// so, it will immediately continue.
await promise;
const contents = await fs.readFile(file, 'utf8');
console.log(contents);
}, Promise.resolve());
}
kshitijrana14
Sure the code does work, but I'm pretty sure it doesn't do what you expect it to do. It just fires off multiple asynchronous calls, but the printFiles function does immediately return after that.
Reading in sequence
If you want to read the files in sequence, you cannot use forEach indeed. Just use a modern for … of loop instead, in which await will work as expected:

async function printFiles () {
const files = await getFilePaths();

for (const file of files) {
const contents = await fs.readFile(file, 'utf8');
console.log(contents);
}
}

Reading in parallel
If you want to read the files in parallel, you cannot use forEach indeed. Each of the async callback function calls does return a promise, but you're throwing them away instead of awaiting them. Just use map instead, and you can await the array of promises that you'll get with Promise.all:

async function printFiles () {
const files = await getFilePaths();

await Promise.all(files.map(async (file) => {
const contents = await fs.readFile(file, 'utf8')
console.log(contents)
}));
}
sandhya6gczb
Use the below code

async function printFiles () {
const files = await getFilePaths()

for await (const contents of files.map(file => fs.readFile(file, 'utf8'))) {
console.log(contents)
}
}

Login / Signup to Answer the Question.