遍历数组forEach,for..of,map方法传递异步函数时遇到了一些奇怪的问题。查看了几篇文章,总结一下看到的内容:
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); }}复制代码
for ...of遍历数组可以得到按顺序执行await期待得到的结果
在chrome console中执行结果?
async function ddd(){ let a = [0,1,2,3,4,5,6,7,8,9]; for(let aa of a){ await setTimeout(function(){ console.log(aa)},1000-aa*100); }}执行结果:9876543210复制代码
Using Babel will transform async/await to generator function and using forEach means that each iteration has an individual generator function, which has nothing to do with the others. so they will be executed independently and has no context of next() with others. Actually, a simple for() loop also works because the iterations are also in one single generator function.
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) }));}复制代码
使用Promise.all(map())可以并行执行并得到一个promise数组
chrome console执行结果:?
async function ddd(){ let a = [0,1,2,3,4,5,6,7,8,9]; await Promise.all(a.map(async (aa)=>{ await setTimeout(function(){ console.log(aa)},1000-aa*100)}));}执行结果:9876543210复制代码
To me using Promise.all() with map() is a bit difficult to understand and verbose, but if you want to do it in plain JS that's your best shot I guess. If you don't mind adding a module, I implemented the Array iteration methods so they can be used in a very straightforward way with async/await. An example with your case:
const { forEach } = require('p-iteration');const fs = require('fs-promise');async function printFiles () { const files = await getFilePaths(); await forEach(files, async (file) => { const contents = await fs.readFile(file, 'utf8'); console.log(contents); });}printFiles()复制代码
引入p-iteration模块也可以解决问题
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());}复制代码
利用数组的reduce()方法传入一个resolved promise作为初始值,链式执行promise,异步函数会按顺序执行且每次只执行一个
chrom console执行:?
async function ccc () { const files = [0,1,2,3,4,5,6,7,8,9]; 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 setTimeout(function(){ console.log(file),1000-file*100}) console.log(contents) }, Promise.resolve());}执行结果:0123456789复制代码
reduce()方法介绍:
The reduce() method executes a reducer function (that you provide) on each member of the array resulting in a single output value.
syntax: arr.reduce(callback[, initialValue])
description: reduce() executes the callback function once for each element present in the array, excluding holes in the array, receiving four arguments:
- accumulator
- currentValue
- currentIndex
- array
The first time the callback is called, accumulator and currentValue can be one of two values. If initialValue is provided in the call to reduce(), then accumulator will be equal to initialValue, and currentValue will be equal to the first value in the array. If no initialValue is provided, then accumulator will be equal to the first value in the array, and currentValue will be equal to the second.
然而越看越晕,并没有搞懂这个问题?
参考文章链接: