在async/await
循环中使用forEach
是否有任何问题?我试图在每个文件的内容上遍历文件数组和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
所以我只是想问这个是否有任何问题。
答案 0 :(得分:1351)
当然代码确实有效,但我很确定它没有按照您的预期执行。它只是触发多个异步调用,但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
回调函数调用都会返回一个promise,但是你将它们丢弃而不是等待它们。只需使用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)
}));
}
答案 1 :(得分:105)
使用ES2018,您可以大大简化以上所有答案:
async function printFiles () {
const files = await getFilePaths()
for await (const file of fs.readFile(file, 'utf8')) {
console.log(contents)
}
}
请参阅规范:https://github.com/tc39/proposal-async-iteration
2018-09-10:这个答案最近受到了很多关注,请参阅Axel Rauschmayer的博客文章,了解有关异步迭代的更多信息:http://2ality.com/2016/10/asynchronous-iteration.html
答案 2 :(得分:29)
而不是将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());
}
答案 3 :(得分:25)
npm上的p-iteration模块实现了Array迭代方法,因此可以使用async / await以非常简单的方式使用它们。
您案例的一个例子:
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);
});
})();
答案 4 :(得分:14)
以下是一些forEachAsync
原型。请注意,您需要await
他们:
Array.prototype.forEachAsync = async function (fn) {
for (let t of this) { await fn(t) }
}
Array.prototype.forEachAsyncParallel = async function (fn) {
await Promise.all(this.map(fn));
}
注意虽然您可以在自己的代码中包含此内容,但不应将其包含在您分发给其他人的库中(以避免污染其全局内容)。
答案 5 :(得分:6)
此解决方案也经过内存优化,因此您可以在10,000个数据项和请求上运行它。这里的其他一些解决方案会使服务器在大型数据集上崩溃。
在TypeScript中:
export async function asyncForEach<T>(array: Array<T>, callback: (item: T, index: number) => void) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index);
}
}
如何使用?
await asyncForEach(receipts, async (eachItem) => {
await ...
})
答案 6 :(得分:4)
用于替换无效的 forEach()
await 循环的简单插入式解决方案是将 forEach
替换为 map
并将 Promise.all(
添加到开头。
例如:
await y.forEach(async (x) => {
到
await Promise.all(y.map(async (x) => {
最后需要一个额外的 )
。
答案 7 :(得分:3)
从循环中调用异步方法不好。这是因为每次循环迭代都会被延迟,直到整个异步操作完成。那不是很有性能。它还避免了 async
/await
的并行化优势。
更好的解决方案是一次性创建所有 promise,然后使用 Promise.all()
访问结果。否则,在前一个操作完成之前,每个后续操作都不会开始。
因此,代码可能会被重构如下;
const printFiles = async () => {
const files = await getFilePaths();
const results = [];
files.forEach((file) => {
results.push(fs.readFile(file, 'utf8'));
});
const contents = await Promise.all(results);
console.log(contents);
}
答案 8 :(得分:3)
您可以使用Array.prototype.forEach
,但是async / await不太兼容。这是因为期望从异步回调返回的承诺将被解决,但是Array.prototype.forEach
不会从其回调的执行中解决任何承诺。因此,您可以使用forEach,但是您必须自己处理Promise解决方案。
这是一种使用Array.prototype.forEach
async function printFilesInSeries () {
const files = await getFilePaths()
let promiseChain = Promise.resolve()
files.forEach((file) => {
promiseChain = promiseChain.then(() => {
fs.readFile(file, 'utf8').then((contents) => {
console.log(contents)
})
})
})
await promiseChain
}
这里(仍然使用Array.prototype.forEach
)是一种并行打印文件内容的方法
async function printFilesInParallel () {
const files = await getFilePaths()
const promises = []
files.forEach((file) => {
promises.push(
fs.readFile(file, 'utf8').then((contents) => {
console.log(contents)
})
)
})
await Promise.all(promises)
}
答案 9 :(得分:2)
在文件中弹出几个方法非常轻松,这些方法将按序列化顺序处理异步数据,并为您的代码提供更传统的风格。例如:
module.exports = function () {
var self = this;
this.each = async (items, fn) => {
if (items && items.length) {
await Promise.all(
items.map(async (item) => {
await fn(item);
}));
}
};
this.reduce = async (items, fn, initialValue) => {
await self.each(
items, async (item) => {
initialValue = await fn(initialValue, item);
});
return initialValue;
};
};
现在,假设已保存在'./myAsync.js',您可以在相邻文件中执行类似下面的操作:
...
/* your server setup here */
...
var MyAsync = require('./myAsync');
var Cat = require('./models/Cat');
var Doje = require('./models/Doje');
var example = async () => {
var myAsync = new MyAsync();
var doje = await Doje.findOne({ name: 'Doje', noises: [] }).save();
var cleanParams = [];
// FOR EACH EXAMPLE
await myAsync.each(['bork', 'concern', 'heck'],
async (elem) => {
if (elem !== 'heck') {
await doje.update({ $push: { 'noises': elem }});
}
});
var cat = await Cat.findOne({ name: 'Nyan' });
// REDUCE EXAMPLE
var friendsOfNyanCat = await myAsync.reduce(cat.friends,
async (catArray, friendId) => {
var friend = await Friend.findById(friendId);
if (friend.name !== 'Long cat') {
catArray.push(friend.name);
}
}, []);
// Assuming Long Cat was a friend of Nyan Cat...
assert(friendsOfNyanCat.length === (cat.friends.length - 1));
}
答案 10 :(得分:2)
上述两种解决方案都可行,但是,安东尼奥用较少的代码完成工作,以下是它如何帮助我从数据库中解析数据,从几个不同的子引用,然后将它们全部推入数组并在一个承诺中解决它毕竟完成了:
Promise.all(PacksList.map((pack)=>{
return fireBaseRef.child(pack.folderPath).once('value',(snap)=>{
snap.forEach( childSnap => {
const file = childSnap.val()
file.id = childSnap.key;
allItems.push( file )
})
})
})).then(()=>store.dispatch( actions.allMockupItems(allItems)))
答案 11 :(得分:1)
一个重要的警告是:await + for .. of
方法和forEach + async
方式实际上有不同的效果。
在await
循环中使用for
将确保逐个执行所有异步调用。并且forEach + async
方式将同时触发所有承诺,这更快但有时不堪重负(如果您进行一些数据库查询或访问某些具有数量限制的Web服务并且不想要一次发射100,000个电话)。
如果您不使用reduce + promise
并且想要确保文件一个接一个地读取 ,您也可以使用async/await
(不太优雅)。
files.reduce((lastPromise, file) =>
lastPromise.then(() =>
fs.readFile(file, 'utf8')
), Promise.resolve()
)
或者您可以创建一个forEachAsync来帮助,但基本上使用相同的循环底层。
Array.prototype.forEachAsync = async function(cb){
for(let x of this){
await cb(x);
}
}
答案 12 :(得分:1)
背景:我昨晚遇到了类似的情况。我使用 async 函数作为 foreach 参数。结果出乎意料。当我对我的代码进行 3 次测试时,它运行了 2 次没有问题并且失败了 1 次。 (奇怪的东西)
我终于明白了并做了一些便笺簿测试。
const getPromise = (time) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`Promise resolved for ${time}s`)
}, time)
})
}
const main = async () => {
const myPromiseArray = [getPromise(1000), getPromise(500), getPromise(3000)]
console.log('Before For Each Loop')
myPromiseArray.forEach(async (element, index) => {
let result = await element;
console.log(result);
})
console.log('After For Each Loop')
}
main();
for - of
循环作为上面建议的 @Bergiconst getPromise = (time) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`Promise resolved for ${time}s`)
}, time)
})
}
const main = async () => {
const myPromiseArray = [getPromise(1000), getPromise(500), getPromise(3000)]
console.log('Before For Each Loop')
// AVOID USING THIS
// myPromiseArray.forEach(async (element, index) => {
// let result = await element;
// console.log(result);
// })
// This works well
for (const element of myPromiseArray) {
let result = await element;
console.log(result)
}
console.log('After For Each Loop')
}
main();
如果你像我一样有点老派,你可以简单地使用经典的 for 循环,这也行:)
const getPromise = (time) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`Promise resolved for ${time}s`)
}, time)
})
}
const main = async () => {
const myPromiseArray = [getPromise(1000), getPromise(500), getPromise(3000)]
console.log('Before For Each Loop')
// AVOID USING THIS
// myPromiseArray.forEach(async (element, index) => {
// let result = await element;
// console.log(result);
// })
// This works well too - the classic for loop :)
for (let i = 0; i < myPromiseArray.length; i++) {
const result = await myPromiseArray[i];
console.log(result);
}
console.log('After For Each Loop')
}
main();
我希望这对某人有所帮助,美好的一天,干杯!
答案 13 :(得分:1)
除了@Bergi’s answer之外,我还想提供第三种选择。它与@ Bergi的第二个例子非常相似,但不是单独等待每个readFile
,而是创建一个承诺数组,每个承诺都在等待。
import fs from 'fs-promise';
async function printFiles () {
const files = await getFilePaths();
const promises = files.map((file) => fs.readFile(file, 'utf8'))
const contents = await Promise.all(promises)
contents.forEach(console.log);
}
请注意,传递给.map()
的函数不需要是async
,因为fs.readFile
无论如何都会返回Promise对象。因此promises
是一个Promise对象数组,可以发送到Promise.all()
。
在@ Bergi的回答中,控制台可能无序地记录文件内容。例如,如果一个非常小的文件在一个非常大的文件之前完成读取,它将被首先记录,即使小文件在<{em> files
数组中的大文件之后。但是,在上面的方法中,您可以保证控制台将按照读取的顺序记录文件。
答案 14 :(得分:1)
使用Task,futurize和一个可遍历的List,你可以简单地执行
async function printFiles() {
const files = await getFiles();
List(files).traverse( Task.of, f => readFile( f, 'utf-8'))
.fork( console.error, console.log)
}
以下是你如何设置
的方法import fs from 'fs';
import { futurize } from 'futurize';
import Task from 'data.task';
import { List } from 'immutable-ext';
const future = futurizeP(Task)
const readFile = future(fs.readFile)
构建所需代码的另一种方法是
const printFiles = files =>
List(files).traverse( Task.of, fn => readFile( fn, 'utf-8'))
.fork( console.error, console.log)
或者甚至可能更具功能性
// 90% of encodings are utf-8, making that use case super easy is prudent
// handy-library.js
export const readFile = f =>
future(fs.readFile)( f, 'utf-8' )
export const arrayToTaskList = list => taskFn =>
List(files).traverse( Task.of, taskFn )
export const readFiles = files =>
arrayToTaskList( files, readFile )
export const printFiles = files =>
readFiles(files).fork( console.error, console.log)
然后从父函数
async function main() {
/* awesome code with side-effects before */
printFiles( await getFiles() );
/* awesome code with side-effects after */
}
如果你真的想要更灵活的编码,你可以这样做(为了好玩,我正在使用建议的Pipe Forward operator)
import { curry, flip } from 'ramda'
export const readFile = fs.readFile
|> future,
|> curry,
|> flip
export const readFileUtf8 = readFile('utf-8')
PS - 我没有在控制台上尝试这个代码,可能会有一些错别字......“直接自由泳,离开圆顶顶部!”正如90年代的孩子们会说的那样。 :-P
答案 15 :(得分:1)
编写自己的 asyncForEach
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array)
}
}
你可以这样使用
await asyncForEach(array, async function(item,index,array){
//await here
}
)
答案 16 :(得分:1)
今天,我遇到了多种解决方案。在forEach循环中运行async等待函数。通过构建包装器,我们可以实现这一目标。
可以通过多种方式完成操作,如下所示,
方法1:使用包装器。
await (()=>{
return new Promise((resolve,reject)=>{
items.forEach(async (item,index)=>{
try{
await someAPICall();
} catch(e) {
console.log(e)
}
count++;
if(index === items.length-1){
resolve('Done')
}
});
});
})();
方法2:使用与Array.prototype的通用函数相同的方法
Array.prototype.forEachAsync.js
if(!Array.prototype.forEachAsync) {
Array.prototype.forEachAsync = function (fn){
return new Promise((resolve,reject)=>{
this.forEach(async(item,index,array)=>{
await fn(item,index,array);
if(index === array.length-1){
resolve('done');
}
})
});
};
}
用法:
require('./Array.prototype.forEachAsync');
let count = 0;
let hello = async (items) => {
// Method 1 - Using the Array.prototype.forEach
await items.forEachAsync(async () => {
try{
await someAPICall();
} catch(e) {
console.log(e)
}
count++;
});
console.log("count = " + count);
}
someAPICall = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("done") // or reject('error')
}, 100);
})
}
hello(['', '', '', '']); // hello([]) empty array is also be handled by default
方法3:
使用Promise.all
await Promise.all(items.map(async (item) => {
await someAPICall();
count++;
}));
console.log("count = " + count);
方法4:传统for循环或现代for循环
// Method 4 - using for loop directly
// 1. Using the modern for(.. in..) loop
for(item in items){
await someAPICall();
count++;
}
//2. Using the traditional for loop
for(let i=0;i<items.length;i++){
await someAPICall();
count++;
}
console.log("count = " + count);
答案 17 :(得分:0)
要查看如何解决问题,请在方法末尾打印console.log。
通常会出错的地方:
这些并不总是错误的,但在标准用例中经常出现。
通常,使用forEach将导致除最后一个以外的所有结果。它将在不等待功能的情况下调用每个函数,这意味着它告诉所有功能启动然后在不等待功能完成的情况下完成。
import fs from 'fs-promise'
async function printFiles () {
const files = (await getFilePaths()).map(file => fs.readFile(file, 'utf8'))
for(const file of files)
console.log(await file)
}
printFiles()
这是本机JS中的一个示例,它将保留顺序,防止函数过早返回,并在理论上保持最佳性能。
这将:
使用此解决方案,将在第一个文件可用时立即显示它,而不必等待其他文件首先可用。
它还将同时加载所有文件,而不必等待第一个文件完成才可以开始读取第二个文件。
此版本和原始版本的唯一缺点是,如果一次开始多次读取,则由于一次可能发生更多错误,因此更难以处理错误。
使用一次读取一个文件的版本,然后将在发生故障时停止,而不会浪费时间尝试读取更多文件。即使采用了精心设计的取消系统,也很难避免它在第一个文件上失败,但同时也已经读取了大多数其他文件。
性能并非总是可预测的。尽管许多系统使用并行文件读取会更快,但有些系统会更喜欢顺序读取。有些是动态的,可能会在负载下转移,提供延迟的优化在争用激烈的情况下并不总是能产生良好的吞吐量。
在该示例中也没有错误处理。如果某些事情要求它们要么全部成功显示,要么根本不显示,就不会这样做。
建议在每个阶段使用console.log进行深度试验,并使用伪造的文件读取解决方案(改为随机延迟)。尽管许多解决方案在简单的情况下似乎都执行相同的操作,但所有解决方案都有细微的差异,因此需要更多的审查才能挤出。
使用此模拟可以帮助您区分解决方案之间的区别:
(async () => {
const start = +new Date();
const mock = () => {
return {
fs: {readFile: file => new Promise((resolve, reject) => {
// Instead of this just make three files and try each timing arrangement.
// IE, all same, [100, 200, 300], [300, 200, 100], [100, 300, 200], etc.
const time = Math.round(100 + Math.random() * 4900);
console.log(`Read of ${file} started at ${new Date() - start} and will take ${time}ms.`)
setTimeout(() => {
// Bonus material here if random reject instead.
console.log(`Read of ${file} finished, resolving promise at ${new Date() - start}.`);
resolve(file);
}, time);
})},
console: {log: file => console.log(`Console Log of ${file} finished at ${new Date() - start}.`)},
getFilePaths: () => ['A', 'B', 'C', 'D', 'E']
};
};
const printFiles = (({fs, console, getFilePaths}) => {
return async function() {
const files = (await getFilePaths()).map(file => fs.readFile(file, 'utf8'));
for(const file of files)
console.log(await file);
};
})(mock());
console.log(`Running at ${new Date() - start}`);
await printFiles();
console.log(`Finished running at ${new Date() - start}`);
})();
答案 18 :(得分:0)
正如其他答案所提到的,您可能希望它按顺序而不是并行执行。 IE。运行第一个文件,等到它完成,然后一旦它完成运行第二个文件。这不会发生。
我认为解决为什么不会发生这种情况很重要。
想想 forEach
是如何工作的。我找不到来源,但我认为它的工作原理如下:
const forEach = (arr, cb) => {
for (let i = 0; i < arr.length; i++) {
cb(arr[i]);
}
};
现在想想当你做这样的事情时会发生什么:
forEach(files, async logFile(file) {
const contents = await fs.readFile(file, 'utf8');
console.log(contents);
});
在 forEach
的 for
循环中,我们调用 cb(arr[i])
,它最终是 logFile(file)
。 logFile
函数内部有一个 await
,所以可能 for
循环会在继续执行 await
之前等待这个 i++
?
不,不会。令人困惑的是,这不是 await
的工作方式。来自the docs:
await 拆分执行流,允许异步函数的调用者恢复执行。在 await 推迟 async 函数的继续之后,随后的语句的执行会随之而来。如果此 await 是其函数执行的最后一个表达式,则继续向函数调用者返回一个挂起的 Promise 以完成 await 的函数并恢复该调用者的执行。
因此,如果您有以下内容,则不会在 "b"
之前记录数字:
const delay = (ms) => {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
};
const logNumbers = async () => {
console.log(1);
await delay(2000);
console.log(2);
await delay(2000);
console.log(3);
};
const main = () => {
console.log("a");
logNumbers();
console.log("b");
};
main();
回到forEach
,forEach
就像main
而logFile
就像logNumbers
。 main
不会因为 logNumbers
做了一些await
操作而停止,而 forEach
不会仅仅因为 logFile
做了一些 await
操作而停止.
答案 19 :(得分:0)
就像@Bergi的回复,但有一个区别。
Promisse.all拒绝所有的诺言,如果一个人被拒绝了。
因此,请使用递归。
const printFiles async = () => {
const files = await getFilePaths();
const readFilesQueue = async (files, index = 0) {
const contents = await fs.readFile(files[index], 'utf8')
console.log(contents)
return files.length <= index
? readFilesQueue(files, ++index)
: files
}
await readFilesQueue(files)
}
printFiles()
PS
readFilesQueue
位于printFiles内部,导致console.log引入副作用,因此,具有返回内容的功能并不酷。
因此,可以通过以下方式简单地设计代码:三个分离的函数“纯”且不引入副作用,可以处理整个列表,并且可以轻松地成型以处理失败的案例。
const files = await getFilesPath()
const printFile = async (file) => {
const content = await fs.readFile(file, 'utf8')
console.log(content)
}
const readFiles = async = (files, index = 0) => {
await printFile(files[index])
return files.lengh <= index
? readFiles(files, ++index)
: files
}
readFiles(files)
未来的编辑/当前状态
Node支持顶级的await(这还没有插件,没有,并且可以通过和声标志实现),这很酷,但是并不能解决一个问题(从策略上讲,我只在LTS版本上工作)。如何获取文件?
使用合成。给定代码,使我感到这是在模块内部的,因此,应该有一个函数来执行它。如果不是这样,您应该使用IIFE和IIFE将角色代码包装到一个异步函数中,以创建一个简单的模块来为您完成所有工作,或者可以采用严格的方法进行合成。
// more complex version with IIFE to a single module
(async (files) => readFiles(await files())(getFilesPath)
请注意,变量的名称会因语义而变化。您传递一个函子(一个可以被另一个函数调用的函数),并在内存中接收一个指针,该指针包含应用程序的初始逻辑块。
但是,如果不是模块,您需要导出逻辑吗?
将功能包装在异步功能上。
export const readFilesQueue = async () => {
// ... to code goes here
}
或更改变量名称,无论如何...
答案 20 :(得分:0)
只需添加到原始答案
async function printFiles() {
const files = await getFilePaths();
const fileReadPromises = [];
const readAndLogFile = async filePath => {
const contents = await fs.readFile(file, "utf8");
console.log(contents);
return contents;
};
files.forEach(file => {
fileReadPromises.push(readAndLogFile(file));
});
await Promise.all(fileReadPromises);
}
async function printFiles() {
const files = await getFilePaths();
for (let i = 0; i < files.length; i++) {
const file = files[i];
const contents = await fs.readFile(file, "utf8");
console.log(contents);
}
}
答案 21 :(得分:0)
fs
基于承诺时, Bergi's solution可以很好地工作。
您可以为此使用bluebird
,fs-extra
或fs-promise
。
但是,节点的本机fs
库的解决方案如下:
const result = await Promise.all(filePaths
.map( async filePath => {
const fileContents = await getAssetFromCache(filePath, async function() {
// 1. Wrap with Promise
// 2. Return the result of the Promise
return await new Promise((res, rej) => {
fs.readFile(filePath, 'utf8', function(err, data) {
if (data) {
res(data);
}
});
});
});
return fileContents;
}));
注意:
require('fs')
强制将函数作为第三个参数,否则会引发错误:
TypeError [ERR_INVALID_CALLBACK]: Callback must be a function
答案 22 :(得分:0)
类似于Antonio Val的p-iteration
,另一个npm模块是async-af
:
const AsyncAF = require('async-af');
const fs = require('fs-promise');
function printFiles() {
// since AsyncAF accepts promises or non-promises, there's no need to await here
const files = getFilePaths();
AsyncAF(files).forEach(async file => {
const contents = await fs.readFile(file, 'utf8');
console.log(contents);
});
}
printFiles();
或者,async-af
有一个静态方法(log / logAF)记录承诺的结果:
const AsyncAF = require('async-af');
const fs = require('fs-promise');
function printFiles() {
const files = getFilePaths();
AsyncAF(files).forEach(file => {
AsyncAF.log(fs.readFile(file, 'utf8'));
});
}
printFiles();
但是,该库的主要优点是您可以链接异步方法来执行以下操作:
const aaf = require('async-af');
const fs = require('fs-promise');
const printFiles = () => aaf(getFilePaths())
.map(file => fs.readFile(file, 'utf8'))
.forEach(file => aaf.log(file));
printFiles();
答案 23 :(得分:-1)
如果您想同时迭代所有元素:
async function asyncForEach(arr, fn) {
await Promise.all(arr.map(fn));
}
如果您想非并行地遍历所有元素(例如,当您的映射函数有副作用或一次在所有数组元素上运行mapper会浪费资源):
选项A:承诺
function asyncForEachStrict(arr, fn) {
return new Promise((resolve) => {
arr.reduce(
(promise, cur, idx) => promise
.then(() => fn(cur, idx, arr)),
Promise.resolve(),
).then(() => resolve());
});
}
选项B:异步/等待
async function asyncForEachStrict(arr, fn) {
for (let idx = 0; idx < arr.length; idx += 1) {
const cur = arr[idx];
await fn(cur, idx, arr);
}
}
答案 24 :(得分:-1)
exports.getTat = async function () {
for (const tatfcp of resp[0]) {
const getProductResponcekey = params.pincode + '-' + tatfcp.productid + '-' + result[tatfcp.productid].reqQty + '-' + tatfcp.groups[0].dispatchwarehouseid;
const redisResp = await redis.getRedis(getProductResponcekey);
if (redisResp) {
products.push(redisResp[0]);
console.log('redis', redisResp[0]);
} else {
const getProductResponceData = await getProductResponce(resp[1], resp[2], params.pincode, tatfcp, data[1], data[2], data[8], gstandvendordata[1], data[9]);
products.push(getProductResponceData);
redis.setRedis(getProductResponcekey, getProductResponceData, config.redis.expiryTime1Day);
}
}
};
这是我的解决方案
答案 25 :(得分:-3)
我会使用经过充分测试的(每周数百万次下载)pify和async模块。如果您不熟悉异步模块,我强烈建议您查看its docs。我发现多个开发人员浪费时间重新创建它的方法,或者更糟糕的是,当高阶异步方法简化代码时,制作难以维护的异步代码。
const async = require('async')
const fs = require('fs-promise')
const pify = require('pify')
async function getFilePaths() {
return Promise.resolve([
'./package.json',
'./package-lock.json',
]);
}
async function printFiles () {
const files = await getFilePaths()
await pify(async.eachSeries)(files, async (file) => { // <-- run in series
// await pify(async.each)(files, async (file) => { // <-- run in parallel
const contents = await fs.readFile(file, 'utf8')
console.log(contents)
})
console.log('HAMBONE')
}
printFiles().then(() => {
console.log('HAMBUNNY')
})
// ORDER OF LOGS:
// package.json contents
// package-lock.json contents
// HAMBONE
// HAMBUNNY
```
&#13;