6

Been fighting with async module for half a day but can't get it to work properly when nesting few levels.

So this works ok:


    var async = require('async')

    var myarr = ["Outer - A", "Outer - B"];
    var myarr2 = ["Inner - A", "Inner - B"];
    var innerComplete = true;

    async.eachSeries(myarr, function( item, outerCallback) {
        console.log('Processing item ' + item);
        async.series([
            function(callback) {
                takeTime(2000, item, callback)
            },
            function(callback) {
                takeTime(1000, item, callback)
            },
            function(callback) {


                outerCallback();
            }
        ], function(err) {
            console.log("---OUTER SEQUENCE---")

        })
    }, function(err){
        console.log("---OUTER LOOP---")

    });

    function takeTime(ms, msg, callback) {
        console.log("Starting " + ms + " ms task from " + msg);
        setTimeout( function() { 
            console.log("Finished " + ms + " ms task from " + msg);
            callback();
        }, ms);
    } 

And it outputs everything nicely in sequence like this:

Processing item Outer - A
Starting 2000 ms task from Outer - A
Finished 2000 ms task from Outer - A
Starting 1000 ms task from Outer - A
Finished 1000 ms task from Outer - A
Processing item Outer - B
Starting 2000 ms task from Outer - B
Finished 2000 ms task from Outer - B
Starting 1000 ms task from Outer - B
Finished 1000 ms task from Outer - B
---OUTER LOOP---

But when I try to nest another eachSeries loop into it like this:


    var async = require('async')

    var myarr = ["Outer - A", "Outer - B"];
    var myarr2 = ["Inner - A", "Inner - B"];
    var innerComplete = true;

    async.eachSeries(myarr, function( item, outerCallback) {
        console.log('Processing item ' + item);
        async.series([
            function(callback) {
                takeTime(2000, item, callback)
            },
            function(callback) {
                takeTime(1000, item, callback)
            },
            function(callback) {
                async.eachSeries(myarr2, function( item2, outerCallback2) {
                    console.log('Processing item ' + item2);
                    async.series([
                        function(callback2) {
                            takeTime(2000, item2, callback2)
                        },
                        function(callback2) {
                            takeTime(1000, item2, callback2)
                        }
                    ], function(err) {
                        console.log('---INNER SEQUENCE---')

                    })
                }, function(err){
                    console.log("---INNER LOOP---")
                });

                outerCallback();
            }
        ], function(err) {
            console.log("---OUTER SEQUENCE---")

        })
    }, function(err){
        console.log("---OUTER LOOP---")

    });

    function takeTime(ms, msg, callback) {
        console.log("Starting " + ms + " ms task from " + msg);
        setTimeout( function() { 
            console.log("Finished " + ms + " ms task from " + msg);
            callback();
        }, ms);
    } 

It loses the execution order when entering the second eachSeries loop like this:

Processing item Outer - A
Starting 2000 ms task from Outer - A
Finished 2000 ms task from Outer - A
Starting 1000 ms task from Outer - A
Finished 1000 ms task from Outer - A
Processing item Inner - A
Starting 2000 ms task from Inner - A
Processing item Outer - B
Starting 2000 ms task from Outer - B
Finished 2000 ms task from Inner - A
Starting 1000 ms task from Inner - A
Finished 2000 ms task from Outer - B
Starting 1000 ms task from Outer - B
Finished 1000 ms task from Inner - A
---INNER SEQUENCE---
Finished 1000 ms task from Outer - B
Processing item Inner - A
Starting 2000 ms task from Inner - A
---OUTER LOOP---
Finished 2000 ms task from Inner - A
Starting 1000 ms task from Inner - A
Finished 1000 ms task from Inner - A
---INNER SEQUENCE---

I also tried out waterfall, mapSeries etc, but with same or otherwise messed up sequence of execution. Am I doing something wrong or doesn't the async module support such nesting?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Timo Wallenius
  • 456
  • 5
  • 16

1 Answers1

10

You're not calling the outerCallback2, you're not calling the callback, and you're calling the outerCallback immediately.

Fixed:

async.eachSeries(myarr, function( item, outerCallback) {
  ,----------------------------------------'
  |  console.log('Processing item ' + item);
  |  async.series([
  |      function(callback) {
  |                 `--------------,
  |          takeTime(2000, item, callback)
  |      },
  |      function(callback) {
  |                 `--------------,
  |          takeTime(1000, item, callback)
  |      },
  |      function(callback) {
  |     ,-----------'
  |     |     async.eachSeries(myarr2, function( item2, outerCallback2) {
  |     |    ,---------------------------------------------'
  |     |    |   console.log('Processing item ' + item2);
  |     |    |   async.series([
  |     |    |      function(callback2) {
  |     |    |          takeTime(2000, item2, callback2)
  |     |    |      },
  |     |    |      function(callback2) {
  |     |    |          takeTime(1000, item2, callback2)
  |     |    |      }
  |     |    |  ], function(err) {
  |     |    |      console.log('---INNER SEQUENCE---')
  |     |    `--->  outerCallback2(err); // <<<
  |     |       })
  |     |   }, function(err){
  |     |      console.log("---INNER LOOP---");
  |     `--->  callback(err); // <<<
  |         });
  |     }
  | ], function(err) {
  |      console.log("---OUTER SEQUENCE---")
  `--->  outerCallback(err); // <<<
    })
}, function(err){
    console.log("---OUTER LOOP---")
    console.log("everything done");
});
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Worked wonders and an excellent piece to better grasp the callbacks in a nested structure like this. Million thanks Bergi! – Timo Wallenius Sep 07 '14 at 18:10
  • gosh thanks that was helpful, is there a more 'function-calling based' way to do this though? – timhc22 Dec 17 '15 at 11:11
  • @timhc22: What do you mean by "function-calling based"? If you don't like passing callbacks around and care about return values, you should have a look at promises. – Bergi Dec 17 '15 at 12:48
  • I'm still getting into Node's (and Javascript's) way of working after using mainly Symfony2 and PHP, so still trying to get my head around the best way to break up blocks of code so everything is nice and modular! – timhc22 Dec 17 '15 at 13:35