search

Home  >  Q&A  >  body text

Use async/await and forEach loops to operate

<p>Are there any problems with using <code>async</code>/<code>await</code> inside a <code>forEach</code> loop? I'm trying to loop through an array of files and use <code>await</code> on the contents of each file. </p> <pre class="brush:php;toolbar:false;">import fs from 'fs-promise' async function printFiles () { const files = await getFilePaths() // Assume this function works properly files.forEach(async (file) => { const contents = await fs.readFile(file, 'utf8') console.log(contents) }) } printFiles()</pre> <p>This code does work, but are there any problems with doing so? I was told that I shouldn't use <code>async</code>/<code>await</code> in higher order functions like this, so I wanted to ask if there are any questions. </p>
P粉010967136P粉010967136472 days ago550

reply all(2)I'll reply

  • P粉697408921

    P粉6974089212023-08-21 10:27:16

    Using ES2018 you can greatly simplify all the answers above:

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

    View specification:proposal-async-iteration

    Simplified:

    for await (const results of array) {
        await longRunningTask()
      }
      console.log('I will wait')

    2018-09-10: This answer has been getting a lot of attention lately, see Axel Rauschmayer's blog post for more information on asynchronous iteration.

    reply
    0
  • P粉094351878

    P粉0943518782023-08-21 09:14:18

    Of course, the code does work, but I'm pretty sure it won't work as you expect. It just triggers multiple async calls, but the printFiles function returns immediately after that.

    Read in order

    If you want to read the file sequentially, indeed you cannot use forEach. Instead, you can use a modern for … of loop, where 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);
      }
    }

    Parallel reading

    If you want to read files in parallel, indeed you cannot use forEach. Each async callback function call returns a promise, but you throw them away instead of waiting for them. Instead, you can use map and wait for the resulting array of promises using 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)
      }));
    }

    reply
    0
  • Cancelreply