for循环中的async.waterfall转义for循环

POSTtypes的Form Action中,我们获取Node.JS/Express所有值, Node.JS/Express其保存到MongoDB

一个隐藏的字段决定了前端JavaScript的一个属性的长度,它的值被更新为隐藏字段的值。

这个长度被用在后端(Node)中以迭代项目列表。

我有一个async.waterfall函数和一个for loop里面运行这样的。

 async.waterfall([ function(callback){ var itemLength = req.body.itemLength; var itemProp,itemComponent; var destination; var destinationsArray =[]; for(var k=1; k<=itemLength; k++){ destination = new Destination({ name: req.body['destinationName'+k], }); itemComponent = { "itemCompProp" : req.body['itemCompProp'+k] }; itemProp = new ItemProp({ itemComponent: itemComponent }); itemProp.save(function(err,itemPropSaved){ destination.newProperty = itemPropSaved._id destination.save(function(err,destinationSaved){ if(err){ console.log("Error== " + err); } else{ destinationsArray.push(destinationSaved._id); } }); }); }// End of For callback(null,destinationsArray); }, function(destinationsArray,callback){ var brand = new Brand({ name : req.body.brandName, }); brand.save(function(err,brandSaved){ if(err){ console.log("Error== " + err); }else{ console.log('Brand Saved'); } }); callback(null); } ], function (err, status) { if(err){ req.flash('error', { msg: 'Error Saving Brands' }); console.log("Error : " + err); } else{ console.log("Brand Saved."); req.flash('success', { msg: 'Brand Successfully Added!' }); } }); res.redirect('/redirectSomewhere'); 

当我们运行这个时, destinationsArray首先返回null ,而不是通过for loop ,然后在destinationsArray的长度( itemLength )上返回destinationsArray的正确值。

我们希望这个过程是同步的。 我们也尝试使用封闭包装for Loop但无济于事。

我们不能使用async.eachSeries而不是for Loop因为我只是遍历一个数字属性,而我们没有任何documents to iterate over

任何可行的解决scheme在async.waterfall运行for Loop

欢呼声和感谢提前。

你在那里的代码有几个问题:

  1. callback被调用的地方。
  2. res.redirect()接到呼叫。
  3. for循环。

save()是asynchronous的。 定期for循环将继续而不用等待所有save()调用完成。 这就是为什么destinationsArray是空的。 正如你所说,你不能使用async.eachSeries(),因为你正在遍历数字属性。 但是,你在那里正确的轨道上。 Async.whilst()就是这样做的。 下面是Async.whilst()和callback的正确调用位置的修改后的代码:

 async.waterfall([ function(callback){ var itemLength = req.body.itemLength; var itemProp,itemComponent; var destination; var destinationsArray =[]; var k = 1; // 1st part of for loop: for(k=1; k<=itemLength; k++) async.whilst( function() { return k <= itemLength; // 2nd part of for loop: for(k=1; k<=itemLength; k++) }, function(whilstCb) { destination = new Destination({ name: req.body['destinationName'+k] }); itemComponent = { "itemCompProp" : req.body['itemCompProp'+k] }; itemProp = new ItemProp({ itemComponent: itemComponent }); itemProp.save(function(err,itemPropSaved){ destination.newProperty = itemPropSaved._id destination.save(function(err,destinationSaved){ if(err){ console.log("Error== " + err); } else { destinationsArray.push(destinationSaved._id); } k++; // 3rd part of for loop: for(k=1; k<=itemLength; k++) whilstCb(null); }); }); }, function(err) { // It gets here once the loop is done console.log(destinationsArray); // This array should have all the values pushed callback(null, destinationsArray); } ); }, function(destinationsArray,callback){ var brand = new Brand({ name : req.body.brandName }); brand.save(function(err,brandSaved){ if(err){ console.log("Error== " + err); } else { console.log('Brand Saved'); } callback(null); }); } ], function (err, status) { if(err){ req.flash('error', { msg: 'Error Saving Brands' }); console.log("Error : " + err); } else { console.log("Brand Saved."); req.flash('success', { msg: 'Brand Successfully Added!' }); } res.redirect('/redirectSomewhere'); }); 

它不是那么多for循环导致你的问题,但save是一个asynchronous操作。 for循环完成,并且在任何savecallback有机会完成之前执行callback。

你想要做的是在所有的目标保存callback被执行之后调用async.waterfallcallbackasync.waterfall 。 就像是:

  destination.save(function(err,destinationSaved){ if(err){ console.log("Error== " + err); } else { destinationsArray.push(destinationSaved._id); if (k === itemLength) { // all destination callbacks have completed successfully callback(null, destinationsArray); } } }); 

这个问题与callback(null, destinationsArray);for loop之外调用for loop而不首先检查循环已经完成。

尝试replacecallback(null, destinationsArray); 像这样的东西:

 if (itemLength > 0 && destinationsArray.length === k - 1) { callback(null, destinationsArray); } else { callback(true); } 

上面的检查确保destination.save()成功完成了正确的次数。

我更喜欢djskinner提出的方法。 但是,由于存在save()错误时发生console.log() ,因此callback的destinationsArray可能包含不正确的项目数。 要解决这个问题,你可以确保replaceconsole.log("Error== " + err);callback(err)来返回错误来结束瀑布。 另外, k === itemLength检查不能正确计算应该保存的正确数量的项目。 这应该被replace为k === destinationsArray.length

我做了修改来解决这个问题,并发布了下面的更新版本。

 destination.save(function(err, destinationSaved){ if (err) { callback(err); } else { destinationsArray.push(destinationSaved._id); if (k === destinationsArray.length) { callback(null, destinationsArray); } } }); 

– EDIT–我真的很喜欢Ben用while whilst()发布的解决scheme。 这允许创build一个迭代顺序运行的循环。 欲了解更多信息,请在这里查看npm页面。