Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested async loop pushing to a async queue not calling main callback

I have a async queue that I am pushing to which will do something. The way I generate the items that I need to push into the is by going through a few nested lists form a data object. The queue ends up processing everything but for some reason I can't get to my main callback with the console.log('All done.'). I've remove most the the unnecessary stuff and just left async stuff. What am I doing wrong? Am I missing something?

var q = async.queue(function(task, callback) {
  console.log('hello ' + task);
  callback();
}, 2);

function A(data) {
  B(data, function() {
    // THIS ISN'T getting called. 
    console.log('All done.');
  })
}

function B(data, callback1) {
  var list = [[1,2], [3,4], [5,6]];
  async.each(list, function(item, callback1) {
    async.each(item, function(i, callback2) {
      doWork(i, function() {
        console.log('Work done');
      })
      callback2();
    }, 
    // THIS should be called when everything in this each is done. 
    callback1)
  })
}

function doWork(i, callback3) {
  q.push(i, callback3);
} 
like image 926
owenlero Avatar asked Nov 11 '22 04:11

owenlero


1 Answers

Here's the code with some comments, as talking about callbacks of callbacks is a bit complicated:

function B(data, callback1 //this is what you want to be called) {
  var list = [[1,2], [3,4], [5,6]];

  //async1
  async.each(list, function(item, callback1 //now callback1 is a function passed to your code by `async.each` not the original callback1) {
      //async2 
      async.each(item, function(i, callback2) {
      doWork(i, function() {
        console.log('Work done');
      })
      callback2();
    }, 
    // THIS is actually called, it's just a different function than you think it is 
    callback1)
  })
}

The problem is that you used the same name for both the argument of B and the callback argument of async1 callback function.

So the callback1 inside async1 callback hides the external callback1 and is actually the internal async1 callback which serves to pass control back to the async.each.

Solution is simple: rename the async1 callback parameter, for example:

function B(data, callback1) {
  var list = [[1,2], [3,4], [5,6]];
  async.each(list, function(item, async1_callback) { //here lies the rename
    async.each(item, function(i, callback2) {
      doWork(i, function() {
        console.log('Work done');
      })
      callback2();
    }, 
    // this is now called as expected 
    callback1
    ); 
    // BUT we forgot to call the async1_callback, so let's do it:
    async1_callback();

};

Works as expected.

like image 89
soulcheck Avatar answered Nov 14 '22 23:11

soulcheck