for 循环内的 async.waterfall 转义 for 循环
Posted
技术标签:
【中文标题】for 循环内的 async.waterfall 转义 for 循环【英文标题】:async.waterfall inside a for loop escapes the for loop 【发布时间】:2015-07-02 17:24:23 【问题描述】:在POST
类型的Form Action
上,我们获取Node.JS/Express
中的所有值并尝试将其保存到MongoDB
。
隐藏字段从前端 javascript 确定属性的长度,并且它的值被更新为隐藏字段的值。
这个长度在后端(节点)中用于迭代项目列表。
我有一个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
然后在一定长度(itemLength
) 的目的地上返回正确的destinationsArray
值。
我们希望这个过程是同步的。我们还尝试使用包装for Loop
的闭包,但无济于事。
我们不能使用async.eachSeries
代替for Loop
,因为我只是在迭代一个数字属性并且我们没有任何documents to iterate over
在async.waterfall
内运行for Loop
的任何可行解决方案?
提前干杯和感谢。
【问题讨论】:
【参考方案1】:问题与 callback(null, destinationsArray);
在 for loop
之外被调用有关,而没有先检查循环是否已完成。
尝试将callback(null, destinationsArray);
替换为以下内容:
if (itemLength > 0 && destinationsArray.length === k - 1)
callback(null, destinationsArray);
else
callback(true);
上述检查以确保destination.save()
成功完成正确的次数。
我其实更喜欢 djskinner 提出的方法。但是,由于出现save()
错误时会出现console.log()
,因此回调的destinationsArray
可能包含不正确的项目数。要解决此问题,您可以确保将 console.log("Error== " + err);
替换为 callback(err)
之类的内容,以结束瀑布并返回错误。此外,k === itemLength
检查未正确说明应保存的正确项目数。这应该替换为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 使用 whilst()
发布的解决方案。这允许创建迭代连续运行的循环。欲了解更多信息,请查看 npm 页面here。
【讨论】:
【参考方案2】:导致问题的不是 for 循环,而是 save
是一个异步操作。 for 循环完成并在任何 save
回调有机会完成之前执行回调。
您要做的是在执行完所有目标保存回调后调用async.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);
);
【讨论】:
【参考方案3】:那里的代码有一些问题:
-
回调被调用的地方。
res.redirect() 在哪里被调用。
for 循环。
save() 是异步的。常规 for 循环将继续进行,而无需等待所有 save() 调用完成。这就是destinationsArray 为空的原因。正如您所说,您不能使用 async.eachSeries() 因为您正在遍历数字属性。但是,您在正确的轨道上。 Async.whilst() 就是这样做的。这是带有 Async.whilst() 的修改后的代码和回调的正确调用位置:
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');
);
【讨论】:
像魅力一样工作。完美的。万分感谢!不知道async.whilst
。以上是关于for 循环内的 async.waterfall 转义 for 循环的主要内容,如果未能解决你的问题,请参考以下文章
Node.js 中 For 循环中的 async.waterfall
nodejs 和 async.waterfall 带有 if 条件和条件函数列表。