提问者:小点点

在forEach循环中使用async/await


foreach循环中使用async/await是否有问题? 我正在尝试循环遍历一个文件数组,并对每个文件的内容执行await

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()

这段代码确实可以工作,但是会不会有什么问题呢? 有人告诉我,您不应该在像这样的高阶函数中使用async/await,所以我只想问问这是否有问题。


共3个答案

匿名用户

当然,代码确实可以工作,但我很确定它没有完成您期望它做的事情。 它只是触发多个异步调用,但printfiles函数在此之后确实会立即返回。

如果您希望按顺序读取文件,则确实不能使用foreach。 只需使用现代的for…of循环,其中await将按预期工作:

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

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

如果您希望并行读取文件,则实际上不能使用foreach。 每一个async回调函数调用都返回一个承诺,但您正在丢弃它们,而不是等待它们。 只需使用map,您就可以等待使用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)
  }));
}

匿名用户

使用ES2018,您可以大大简化以上所有答案:

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

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

参见规范:提案-异步-迭代

2018-09-10:这个答案最近得到了很多关注,请看Axel Rauschmayer的博客文章了解更多关于异步迭代的信息:ES2018:异步迭代

匿名用户

promise.all结合使用array.prototype.map(它不保证解析promise的顺序),我使用array.prototype.reduce,从解析的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());
}