循环同步多个async.whilst

时间:2013-08-18 12:03:55

标签: node.js loops async.js

我想在同步模式下在node.js中使用许多包含的循环。

示例:

for (var i = 0; i < length1; i++) {
  for (var j = 0; j < length2; j++) {
    for (var k = 0; k < length3; k++) {
      //completed 3
    }
    //completed 2
  }
  //do completed 1
}

如何使用异步执行此操作?我试过这个:

exports.myFunction = function (callback) {
  var finalListA = new Array();
  var pos = 0;
  Model_A.find().populate('listOfItems')
    .lean().exec(function (err, As) {
      if (err) {
        console.log(err);
        return callback(err, null);
      } else {
        //For each A
        var i = 0;
        async.whilst(
          function () {
            return i < As.length;
          },
          function (callback1) {
            var isActive = false;
            //For each B into the A
            var j = 0;
            async.whilst(
              function () {
                return j < As[i].Bs.length;
              },
              function (callback2) {
                Model_B.findById(AS[i].Bs[j]._id, function (err, B) {
                  if (err) {} else {
                    var k = 0;
                    // For each C in the B
                    async.whilst(
                      function () {
                        return k < B.Cs.length;
                      },
                      function (callback3) {
                        if (B.Cs[k].dateEnd >= Date.now()) {
                          isActive = true;
                        }
                        k++;
                        callback3();
                      },
                      function (err) {
                        console.log("3 COMPLETED");
                      }
                    );
                  }
                });
                j++;
                callback2();
              },
              function (err) {
                console.log("2 COMPLETED");
                if (err) {} else {
                  if (isActive == true) {
                    finalListA[pos] = As[i];
                    pos = pos + 1;
                  }
                }
              }
            );
            i++;
            callback1();
          },
          function (err) {
            console.log("1 COMPLETED");
            if (err) {} else {
              return callback(null, finalListA);
            }
          }
        );
      }
    });
}

跟踪显示我:

  • 已完成2
  • 已完成2
  • 已完成1
  • 已完成3
  • 已完成3

预期订单是:

  • 已完成3
  • 已完成3
  • 已完成2
  • 已完成2
  • 已完成1

2 个答案:

答案 0 :(得分:1)

您必须在whilst循环的结束回调中调用较高循环的回调(就像您对最外层callback所做的那样),而不是从whilst同步调用它们你只是开始下一级迭代的主体。

不过,我不知道你真正想做什么,但whilst似乎不是迭代数组的最佳选择。使用并行each或序列eachSeries(或其mapreduce等效内容。

答案 1 :(得分:1)

我最近创建了一个名为 wait.for 的简单抽象来在同步模式下调用异步函数(基于Fibers)。它处于早期阶段,但有效。它在:

https://github.com/luciotato/waitfor

使用 wait.for ,您可以调用任何标准nodejs async函数,就像它是同步函数一样。

我不明白你在代码中想要做什么。也许您可以再解释一下您的代码,或者给出一些数据示例。 我没有&#39;知道Model_A或Model_B是什么......我猜你的大部分代码,但是......

使用 wait.for 您的代码migth为:

var wait=require('wait.for');

exports.myFunction = function(callback) {
  //launchs a Fiber
  wait.launchFiber(inAFiber,callback);
}

function inAFiber(callback) {
    var finalListA = new Array();
    var pos = 0;

    var x= Model_A.find().populate('listOfItems').lean();
    As = wait.forMethod(x,"exec");
    //For each A
    for(var i=0;i<As.length;i++){
        var isActive = false;
        //For each B into the A
        for(var j=0; j < As[i].Bs.length;j++){
           var B=wait.forMethod(Model_B,"findById",AS[i].Bs[j]._id);
           // For each C in the B
           for(var k=0; k < B.Cs.length;k++){
              if(B.Cs[k].dateEnd >= Date.now()) {
                  isActive = true;
              }
            }
            console.log("3 COMPLETED");
        }
        console.log("2 COMPLETED");
        if(isActive == true) {
            finalListA[pos] = As[i];
            pos = pos + 1;
        }
    };
    console.log("1 COMPLETED");
    return callback(null,finalListA);
}

另外,对于我所看到的,你应该在找到一个项目(isActive)后立即打破循环,并且你不需要var pos。这样做你的代码将是:

var wait=require('wait.for');

exports.myFunction = function(callback) {
  //launchs a Fiber
  wait.launchFiber(inAFiber,callback);
}

function inAFiber(callback) {
    var finalListA = [];

    var x= Model_A.find().populate('listOfItems').lean();
    As = wait.forMethod(x,"exec");
    var isActive;
    //For each A
    for(var i=0;i<As.length;i++){
        isActive = false;
        //For each B into the A
        for(var j=0; j < As[i].Bs.length;j++){
           var B=wait.forMethod(Model_B,"findById",AS[i].Bs[j]._id);
           // For each C in the B
           for(var k=0; k < B.Cs.length;k++){
              if(B.Cs[k].dateEnd >= Date.now()) {
                  isActive = true;
                  break;//for each C
              }
            } //loop for each C

            console.log("3 COMPLETED");
            if (isActive) break;//for each B

        } //loop for each B
        if (isActive) finalListA.push(As[i]);
        console.log("2 COMPLETED");
    } //loop for each A
    console.log("1 COMPLETED");
    return callback(null,finalListA);
}