質問

I want to use many included loops in node.js in synchronous mode.

Example :

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
}

How to do this with async? I tried this :

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

The trace shows me :

  • COMPLETED 2
  • COMPLETED 2
  • COMPLETED 1
  • COMPLETED 3
  • COMPLETED 3

The order expected is :

  • COMPLETED 3
  • COMPLETED 3
  • COMPLETED 2
  • COMPLETED 2
  • COMPLETED 1
役に立ちましたか?

解決

You must call the callbacks of the higher loops from the end callback of your whilst loop (like you did with the outermost callback), instead of calling them synchronously from the whilst body in which you just started the next level iteration.

Btw, I don't know what you actually want to do, but whilst does not seem the best choice for iterating arrays. Use the parallel each or the serial eachSeries (or their map or reduce equivalents).

他のヒント

I've recently created simpler abstraction called wait.for to call async functions in sync mode (based on Fibers). It's at an early stage but works. It is at:

https://github.com/luciotato/waitfor

Using wait.for, you can call any standard nodejs async function, as if it were a sync function.

I do not understand exactly what are you trying to do in your code. Maybe you can explain your code a little more, or give some data example. I dont' know what Model_A or Model_B are... I'm guessing most of your code, but...

using wait.for your code migth be:

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

Also, for what I see, you should break the loops as soon as you find one item (isActive), and you don't need the var pos. Doing that your code will be:

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);
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top