在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
,所以我只想问问这是否有问题。
当然,代码确实可以工作,但我很确定它没有完成您期望它做的事情。 它只是触发多个异步调用,但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());
}