9

Just trying to get my head around using Async module for NodeJS.

I have the following code.

var a1 = [1,2,3,4,5,6,7,8];
async.forEachSeries(a1, function(n1, callback) {
    console.log(n1);
    var a2 = [10,11,12,13,14];
    async.forEachSeries(a2, function(n2, callback) {
        console.log(n1 + " " + n2);
        callback();
    });
    callback();
});

I want to make the process of the above code in such a way that the print out becomes

1
1 10
1 11
1 12
1 13
1 14
2
2 10
2 11
2 12
2 13
2 14
3
3 10
3 11
3 12
3 13
3 14
.....

But instead I'm getting something like..

1
1 10
2
2 10
1 11
3
3 10
2 11
1 12
....

How do I fix this?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
ericbae
  • 9,604
  • 25
  • 75
  • 108
  • 2
    If you need synchronous output, why do you perform it async? – NilsH Apr 11 '13 at 07:22
  • 1
    hm. doesn't forEachSeries perform in a synchronous way? – ericbae Apr 11 '13 at 07:26
  • Both Node 0.10.3 and 0.8.16 produce the output you want on my Mac. Are you piping the output of the script to a file (or another program)? That changes the behaviour of `process.stdout`, and therefore `console.log` as well, so that might result in different output. And `forEachSeries` is synchronous in that the next iteration will only be called once the previous is done. – robertklep Apr 11 '13 at 07:44
  • Hm.. you're right. On my machine it does in fact produce the output you expected as well. But I would rather call it "in sequence" than "synchronous". I'm using node 0.10.3 btw. – NilsH Apr 11 '13 at 07:45
  • @NilsH I guess it's a matter of semantics :) I'd call it synchronized since the operations are dependent on each other, `(N+1)` only gets called once `(N)` has completed. – robertklep Apr 11 '13 at 08:30
  • @robertklep Yes, but between execution of `(N+1)` and `(N`), other stuff could happen, and it still could be "in sequence". But I agree, it's a matter of sematics :) – NilsH Apr 11 '13 at 08:41
  • Strange, I wasn't piping the output to another program. The solution given by @spotirca worked well for me. – ericbae Apr 11 '13 at 12:43

1 Answers1

17

The forEachMethod also accepts a callback when everything done. So your code should look like this:

var a1 = [1,2,3,4,5,6,7,8];
async.forEachSeries(a1, function(n1, callback_s1) {
    console.log(n1);
    var a2 = [10,11,12,13,14];
    async.forEachSeries(a2, function(n2, callback_s2) {
        console.log(n1 + " " + n2);
        callback_s2();
    }, function () {
        /* Finished the second series, now we mark the iteration of first series done */ 
        callback_s1();
    } );
});

The problem in your code is the fact that you assume async.forEachSeries to be synchronous, but it is not. It guarantees the fact the array will be handled synchronously, but the function itself is asynchronous.

spotirca
  • 471
  • 3
  • 3
  • Could you please expand on "It guarantees the fact the array will be handled synchronously, but the function itself is asynchronous."? If each element of the array is handled synchronously, does that not imply the function applied TO each of the elements is also synchronous?? – ericbae Apr 11 '13 at 12:40
  • Thanks! I had been breaking by head over this for two hours. Your answer cleared up the callback mechanism for nested async.* – Sterex Jan 28 '16 at 09:27