Reputation: 979
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
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
Upvotes: 2
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:
Upvotes: 4
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
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