【问题标题】:async.waterfall inside a for loop escapes the for loopfor 循环内的 async.waterfall 转义 for 循环
【发布时间】: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 的任何可行解决方案?

提前干杯和感谢。

【问题讨论】:

    标签: javascript node.js mongodb asynchronous mongoose


    【解决方案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】:

        那里的代码有一些问题:

        1. 回调被调用的地方。
        2. res.redirect() 在哪里被调用。
        3. 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
        猜你喜欢
        • 1970-01-01
        • 2015-10-26
        • 1970-01-01
        • 2021-10-28
        • 2015-03-21
        • 2015-11-12
        • 1970-01-01
        • 2019-11-10
        • 2018-11-05
        相关资源
        最近更新 更多