mgs
mgs

Reputation: 2689

arguments to javascript callback function

var data = [{offset: 2000, str:'foo'}, {offset: 4000, str:'bar'}];

for (var i=0; i<data.length; i++) {
    var x = data[i];
    setTimeout(function(){printStuff(x.str)}, x.offset);
}

function printStuff(str) {
    console.log(str);
}

I was expecting to get printStuff('foo') at 2000 ms offset and printStuff('bar') at 4000 ms offset but instead it prints 'bar' both times. I've no idea what's going on, help please.

Upvotes: 2

Views: 403

Answers (3)

Denys S&#233;guret
Denys S&#233;guret

Reputation: 382150

Do this :

for (var i = 0; i < data.length; i++) {
    (function (x) {
        setTimeout(function () {
            printStuff(x.str)
        }, x.offset);
    })(data[i]);
}

Your problem is that x has changed in the closure when the function is called.

Upvotes: 3

Brett Zamir
Brett Zamir

Reputation: 14345

setTimeout does not block the code from continuing to execute, so the loop completes, and by the time the setTimeout callback is executed, the latest value for 'x' is the second object in the data array.

Upvotes: 0

Esailija
Esailija

Reputation: 140230

You can use functional iteration that gives a closure for free:

data.forEach( function( x ) {
      setTimeout( printStuff.bind(null, x.str), x.offset );
});

Shims for all in case oldIE support is required:

forEach

bind

Upvotes: 2

Related Questions