1

I have the following code, I am trying to simply count to ten using a FOR loop Through each iteration I want to use jQuery to update a div element with the value of i

for (i=0;i<=10;i++){
  setTimeout(function(){
      $(".test").html(i);
  },10000);
}​

JSFIDDLE

The problem is, the loop will execute and not display anything until finished, which will simply be the number 10.

Is there a way to achieve what I need?

Thank

rjz
  • 16,182
  • 3
  • 36
  • 35
  • 5
    The problem isn't the loop--it's the way you've opted to implement the counter. You're effectively setting 10 timeouts at very-almost-the same moment in time. – rjz May 13 '12 at 22:15
  • 1
    http://jsfiddle.net/zerkms/GgzFW/4/ – zerkms May 13 '12 at 22:16
  • possible dups: http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example and http://stackoverflow.com/questions/10242254/settimeout-in-for-loop-with-random-delay – ajax333221 May 13 '12 at 22:29

3 Answers3

7

Your code doesn't work as expected because of closure effect. It is usually solved by creating another anonymous function that is called right after it is created:

for (i=0;i <= 10;i++){
    (function(i) {
        setTimeout(function(){
            $(".test").html(i);
        }, i * 1000);
    })(i);
}​

http://jsfiddle.net/zerkms/GgzFW/4/

zerkms
  • 249,484
  • 69
  • 436
  • 539
  • 2
    Not a big deal when there's only 10, but JavaScript timers are notoriously inaccurate. If you have several more, I think you'll find that as the timers fire, they begin to happen at varying intervals. If you're going to use `setTimeout` instead of `setInterval`, you should probably have each subsequent one invoked using recursion. – cliffs of insanity May 13 '12 at 22:22
  • 1
    @cliffs of insanity: that depends on aims. Recursive solution also is inaccurate and its total execution time would be always greater than expected. – zerkms May 13 '12 at 22:28
  • 1
    I think that's a fair point. It'll be overall more consistent to the eye (more noticeable in some browsers than others), but it does require some work between the intervals. – cliffs of insanity May 13 '12 at 22:32
  • 1
    @cliffs of insanity: yep. Anyway thanks for the mention and let OP choose whatever better suits his needs – zerkms May 13 '12 at 22:34
2

demo jsFiddle

var i = 0,
    T =setInterval(function(){
        i < 10 ?  $(".test").html(++i) : clearInterval(T);       
    },1000);

$(".test").html(i);
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
1

Try using setInterval() instead:

var i = 0;

var timer = setInterval(function() {
    $('.test').html(i);

    i++;

    if(i > 10) {
        clearInterval(timer);
    }
}, 10000);
​

Your current loop will loop as fast as it can, and set 10 timeouts to occur in approximately 10 seconds after the loop is called. What setInterval() does is call the code in the function passed to it every 10 seconds, in effect delaying the loop.

The if() statement at the end of it stops the interval occurring if i > 10 by clearing the variable the interval was given a reference to.

I've forked your JSFiddle here, with a 100ms wait time instead of 10s for testing purposes.

Bojangles
  • 99,427
  • 50
  • 170
  • 208
  • I was about to comment that you should be using `clearInterval` instead of `clearTimeout`, but it seems to work either way. Do you know if that's reliable across browsers? – cliffs of insanity May 13 '12 at 22:29
  • 1
    @cliffsofinsanity Good catch - thank you. That was just a typo on my part. I don't know if it works cross-browser, but it works in Chromium fine. Stick to `clearInterval()` for `setInterval()`, though :) – Bojangles May 13 '12 at 22:30