2
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.

1
  • it's a scoping issue; when your printStuff finally runs, x has been reassigned to {offset:4000,str:'bar'} Commented Jul 6, 2012 at 14:22

3 Answers 3

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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

2 Comments

I didn't knew this new and interesting function. Do you have precision about the compatibility (including mobiles) ?
@dystroy the compatibility and user-made code to make those functions work in unsupported browsers can be found in the links I gave. Roughly any browser made/patched after december 2009 should support them.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.