Nesting node async.eachSeries
Asked Answered
D

1

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?

Donnydonnybrook answered 7/9, 2014 at 17:9 Comment(0)
M
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");
});
Masao answered 7/9, 2014 at 17:16 Comment(4)
Worked wonders and an excellent piece to better grasp the callbacks in a nested structure like this. Million thanks Bergi!Donnydonnybrook
gosh thanks that was helpful, is there a more 'function-calling based' way to do this though?Quasi
@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.Masao
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!Quasi

© 2022 - 2024 — McMap. All rights reserved.