Javascript for循环中的async.fallower将转义for循环

Javascript for循环中的async.fallower将转义for循环,javascript,node.js,mongodb,asynchronous,mongoose,Javascript,Node.js,Mongodb,Asynchronous,Mongoose,在POST类型的表单操作中,我们获取Node.JS/Express中的所有值,并尝试将其保存到MongoDB中 隐藏字段根据前端javascript确定属性的长度,其值将更新为隐藏字段的值 此长度在后端节点中用于迭代项目列表 我有一个async.瀑布函数和一个for循环,在其中运行,如下所示 async.waterfall([ function(callback){ var itemLength = req.body.itemLength; var itemProp

在POST类型的表单操作中,我们获取Node.JS/Express中的所有值,并尝试将其保存到MongoDB中

隐藏字段根据前端javascript确定属性的长度,其值将更新为隐藏字段的值

此长度在后端节点中用于迭代项目列表

我有一个async.瀑布函数和一个for循环,在其中运行,如下所示

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循环,然后返回destinationsArray在目标的长度itemLength上的正确值

我们希望这个过程是同步的。我们还尝试使用一个封装for循环的闭包,但没有效果

我们不能使用async.eachSeries而不是for循环,因为我只是在迭代一个数值属性,我们没有任何文档可以迭代

在async.瀑布中运行for循环是否有可行的解决方案

干杯并提前感谢。

问题与callbacknull、destinationsArray有关;在for循环外部调用,而不首先检查循环是否已完成

尝试替换callbacknull、destinationsArray;比如说:

if (itemLength > 0 && destinationsArray.length === k - 1)  {
    callback(null, destinationsArray);
} else {
    callback(true);
}
以上检查确保destination.save成功完成正确次数

实际上我更喜欢djskinner提出的方法。但是,由于存在保存错误时会出现console.log,callbacked destinationsArray可能包含不正确的项数。要解决这个问题,您可以确保更换控制台;使用callbackerr之类的工具来结束瀑布,并返回错误。此外,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);
        }
    }
});
-编辑-我真的很喜欢Ben发布的解决方案。这允许在迭代连续运行的地方创建循环。有关更多信息,请查看npm页面。

该问题与callbacknull、destinationsArray有关;在for循环外部调用,而不首先检查循环是否已完成

尝试替换callbacknull、destinationsArray;比如说:

if (itemLength > 0 && destinationsArray.length === k - 1)  {
    callback(null, destinationsArray);
} else {
    callback(true);
}
以上检查确保destination.save成功完成正确次数

实际上我更喜欢djskinner提出的方法。但是,由于存在保存错误时会出现console.log,callbacked destinationsArray可能包含不正确的项数。要解决这个问题,您可以确保更换控制台;使用callbackerr之类的工具来结束瀑布,并返回错误。此外,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);
        }
    }
});

-编辑-我真的很喜欢Ben发布的解决方案。这允许在迭代连续运行的地方创建循环。有关更多信息,请查看npm页面。

与其说是For循环导致了问题,不如说是save是一个异步操作。for循环完成,并且在任何save回调有机会完成之前执行回调

您要做的是在执行了所有目标save回调之后调用async.fallower回调。比如:

         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);
              }
            }
          });

造成问题的与其说是for循环,不如说是save是一个异步操作。for循环完成,并且在任何save回调有机会完成之前执行回调

您要做的是在执行了所有目标save回调之后调用async.fallower回调。比如:

         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);
              }
            }
          });

这里的代码几乎没有问题:

回拨电话的地方。 res.redirect接到电话的地方。 for循环。 保存是异步的。常规for循环将继续,而不等待所有save调用完成。这就是destinationsArray为空的原因。正如您所说的,您不能使用async.eachSeries,因为您正在迭代数值属性。然而,你在这方面走的是对的。Async.while就是这样做的。下面是修改后的代码,其中包含Async.while和回调的正确调用位置:

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'); 
});

这里的代码几乎没有问题:

回拨电话的地方。 res.redirect接到电话的地方。 for循环。 保存是异步的。常规for循环将继续,而不等待所有save调用完成。这就是destinationsArray为空的原因。正如您所说的,您不能使用async.eachSeri 因为您正在迭代数值属性,所以会出现错误。然而,你在这方面走的是对的。Async.while就是这样做的。下面是修改后的代码,其中包含Async.while和回调的正确调用位置:

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.while.Works很有魅力。完美的非常感谢!不知道async.while。