inselberg
inselberg

Reputation: 979

underscore: async each loop waiting "inside"

How can i wait for callbacks inside a loop changing a variable, and still using asynchronicity?

The 2nd example is using async, in this case i don't know how to add a 2nd parameter sum to wait, in order to avoid a global var sum. Called like wait(sum,value); with a return value sum

wait is a representation for a complex function, which i use in my real-problem, so it can't be rewritten into "inline"-code and has to stay "function".

Example1:

var _ = require('underscore');
var arr = [1,2,3,4,5,6,7];
var sum = 0;

function wait(item,callback) {
  setTimeout(function() {
    callback(item);
  }, Math.ceil(Math.random()*1000));
}

var done = _.after(arr.length,function(value) {
  console.log('sum ='+value);
})

_.each(arr,function(itm) {
  wait(itm,function(value) {
    console.log('waiting... '+value);
    sum = sum + value;
  })
 // Please wait for the callback
  console.log(itm);
  done(sum);
});

Example2:

function asyncExample2() {
var async = require('async');
var arr = [1,2,3,4,5,6,7];

function otherWait(item, callback) {
    setTimeout(function() {
    callback(item); // call this when you're done with whatever you're doing
  }, Math.ceil(Math.random()*1000));
}

function wait(item, callback) {
  setTimeout(function() {
    otherWait(item,function() {
    console.log(item);
  });
  callback(item); 
  }, Math.ceil(Math.random()*1000));
}

function done() { console.log("sum = "+sum);};

var sum = 0;
async.forEach(arr, wait, done);
}

Desired Call:

sum = wait(sum,item) 

Upvotes: 2

Views: 7042

Answers (4)

Herrington Darkholme
Herrington Darkholme

Reputation: 6315

You can really do a recursion version without global variable.

  var arr = [1,2,3,4,5,6,7];

  function wait(arr, max, callback, sum, done) {
    var item = arr.shift();
      setTimeout(function(){
        if(item) {
          sum[0] = callback(item, sum[0]);
          sum[1]++;
        }
        else
          sum[1] === max ? done(sum[0]) : wait(arr,max, callback, sum, done);
      }, Math.random()*1000);
      item && wait(arr, max,callback, sum, done);
  }

  function cb(item, acc) {
    console.log('waiting....' + item);
    return item + acc;
  }

  function done(sum) {
     console.log(sum);
  }

  wait(arr, arr.length,cb, [0, 0], done);

Output enter image description here

Upvotes: 2

Herrington Darkholme
Herrington Darkholme

Reputation: 6315

The easiest way to do this is putting done in the function wait. It makes done called only after the last callback is executed.

var arr = [1,2,3,4,5,6,7];
var sum = 0;

function wait(item,callback) {
  setTimeout(function() {
    callback(item);
    done(sum);
  }, Math.ceil(Math.random()*1000));
}

var done = _.after(arr.length,function(value) {
  console.log('sum ='+value);
})

_.each(arr,function(itm) {
  wait(itm,function(value) {
    console.log('waiting... '+value);
    sum = sum + value;
  })
  // Please wait for the callback
  console.log(itm);
  //done(sum);
});

Output:

enter image description here

Upvotes: 4

Sriharsha
Sriharsha

Reputation: 2443

I am assuming that you are using setTimeout to implement the asynchronus behaviour, instead you can use a library like async which handles much more easily for you.

Ex of using async's each

var async = require('async');
var arr = [1,2,3,4,5,6,7];
var sum = 0;

async.forEach(arr, function(item, cb){
   sum = sum + item;
   cb();
}, function(err){
  console.log(sum);
});

Upvotes: 1

Bob Davies
Bob Davies

Reputation: 2282

Underscore is entirely synchronous so done(sum) would execute before wait has finished executing. For asynchronous operation don't use underscore.

Something simple like this should do what you want:

var sum = 0;
var waitNext = function(pos) {
    wait(arr[pos], function(value)) {
        if(pos < arr.length)
        {
            console.log('waiting... '+value);
            sum += value;
            waitNext(pos+1);
        }
        else
        {
            done(sum);
        }
    }
}
waitNext(0);

You could of course avoid using waitNext and just modify wait but this will work if wait is not your code. Not sure if you'd want sum += value inside the if or just before it since now there's an unnecessary waitNext call you could remove by tweaking the if condition's order.

Upvotes: 2

Related Questions