nodejs循环与asynchronous调用数组?

我想通过一个数组来遍历一个new Thing到一个列表,在东西里面它做了一些自己的asynchronous调用。 我将如何以同步的方式迭代数组,因为callback需要列表中的数据正常工作。 由于我的for循环是同步的并且执行一些asynchronous调用,所以如果完成了调用,则在列表之前调用该callback。

我不知道如何迭代数组,并在做callback之前完成所有的工作

 load(file, callback) { fs.readFile(file, (err, fd) => { var data = JSON.parse(fd); for(var i of data.array){ this.list.push(new Thing(i.id)); // new Thing is Asynchronous } callback(); // Needs a finished list return; }); } 

解决了它:

通过将我的Thing类转换为同步,通过去除对类中的函数的asynchronous调用,并首先实例化循环中的所有东西,然后调用Promise.all调用函数,我解决了这个问题:

 load(file, callback) { fs.readFile(file, (err, fd) => { var data = JSON.parse(fd); for(var i of data.array){ this.list.push(new Thing(i.id)); } Promise.all(this.list.map(i => i.load()).then(callback); }); } 

你必须在Thing有一些状态来跟踪它的完成情况,例如你可以有一个实例variables,这是一个承诺。 所以这Thing一起黑了Thing例子

 class Thing { constructor(id) { this.id = id; this.done = new Promise((resolve, reject) => { asyncThingWithCallback((err, data) { if (err) { this.asyncVal = null; reject(err); } else { this.asyncVal = data; resolve() } }) }); } } 

你可以像这样在你的callback中使用done属性:

 load(file, callback) { fs.readFile(file, (err, fd) => { var data = JSON.parse(fd); for(var i of data.array){ this.list.push(new Thing(i.id)); // new Thing is Asynchronous } Promise.all(this.list.map((thing) => thing.done)) .then(callback) }); } 

首先,通常不build议有一个构造函数需要一些asynchronous操作来完成创build一个有效的对象。 这不会导致易于写入或维护的代码,因为构造函数必须返回对象引用,并且因为操作是asynchronous的,所以必须在创build有效对象之前返回该对象引用。 这只会导致混乱,部分创build的对象。 您可以通过要求将完成callback传递给构造函数来确保调用代码不会尝试使用该对象,直到调用完成callback之后才能使其工作,但这不是干净的方式。 这也使得你的asynchronous操作不可能返回一个承诺(这是asynchronousdevise的未来),因为构造函数必须返回对象引用,所以它不能返回承诺。

你可以把诺言embedded到对象中,但是这也很麻烦,因为诺言在最初的asynchronous操作中才真正有用。

通常做的是使构造函数只有同步,然后有一个.init()方法来完成asynchronous部分。 这使得代码更简洁,并且与使用promise的实现兼容。

或者,您可以创build一个工厂函数,返回parsing为对象引用的许诺。

其次,你已经知道,你的for循环同步运行。 在进入循环的下一部分之前,它不会“等待”它内部的任何asynchronous操作。 只要每个循环的调用是分开的,不依赖于先前的迭代,那一切都好。 所有你需要知道的是当循环中的所有asynchronous操作完成,并使你的asynchronous操作返回承诺,并使用Promise.all()通常是最好的工具。

所以,假设你使用了.init()方法,其中.init()做了初始化的async部分,构造函数是同步的, .init()返回一个promise。 那么,你可以这样做:

 // create all the things objects let things = data.array.map(i => new Thing(i.id)); // initialize them all asynchronously Promise.all(things.map(item => { return item.init(); })).then(function() { // all things are asynchronously initialized here }); 

或者,使用工厂函数的概念返回parsing对象的承诺:

 function newThing(i) { let o = new Thing(i.id); return o.init().then(function() { // resolve to the object itself return o; }); } Promise.all(data.array.map(i => newThing(i))).then(things => { // all things in the array ready to be used here }); 

如果你需要对数组迭代进行sorting,那么第二次迭代直到第一次迭代的asynchronous部分完成,第三次迭代才开始,第三次等待,直到第二次迭代完成为止,那么你不能使用for循环,因为它只是简单的不这样工作。 有几种不同的方法来做这种序列化的asynchronous迭代。 您可以在这些其他post中看到几个不同的scheme:

如何同步一系列的承诺?

JavaScript:同步执行一个promise链

ES6的承诺 – 像async.each?

我怎样才能顺序执行shell命令?

您可以使用primise.all在for循环之后运行所有的promise。然后您可以parsingpromise.all。

 load(file) { fs.readFile(file).Then(function (fd){ var data = JSON.parse(fd); var EachPromise = [ ]; for(var i of data.array){ EachPromise.push(new Thing(i.id)); // new Thing is Asynchronous } Promise.all(EachPromise) .then(function (result){ console.log('this is result',result); }).Catch(function (error){ console.log('this is error', error); }); }