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.
3 Answers 3
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.
Comments
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:
2 Comments
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.
printStufffinally runs,xhas been reassigned to{offset:4000,str:'bar'}