2

See the following nodejs code with async:

var async = require('async');

function inc(n, cb) {
    setTimeout(function() {
        cb(null, n+1);
    },1000);
};

var calls = [];

for(i=0;i<3;i++) {
    calls.push(function(cb){
        inc(i, cb);
    });
}

async.parallel(calls, function(err, results) {
    console.log(results);
});

It prints:

[4, 4, 4]

I don't understand why the result isn't [1, 2, 3]?

Freewind
  • 193,756
  • 157
  • 432
  • 708

2 Answers2

2
for(i=0;i<3;i++) {
    calls.push(function(cb){
        inc(i, cb);
    });
}

The functions are getting executed after the end of the for loop; at the time, i equals 3.

You should use another closure here. For example:

for(i=0;i<3;i++) {
    calls.push(function (i) {
        return function (cb) {
            inc(i, cb);
        }
    }(i));
}
penartur
  • 9,792
  • 5
  • 39
  • 50
2

Because every call in calls array references the same i variable, think this code:

function fn() {
    var i = 1;
    setTimeout(function() { alert(i); }, 500);
    i++;
    i++;
}
fn();

This, certainly, would output 3 instead of 1, this is the same issue of your code, the variable i changed before the call executes;

To avoid this problem, wrap for loop with a Immediately Invoked Function Expression to create a new scope to store the value of i

for (var i = 0; i < 3; i++) {
    (function(i) {
        calls.push(function(cb) { inc(i, cb); });
    }(i));
}
otakustay
  • 11,817
  • 4
  • 39
  • 43