0

So I know that setTimeout() function can trigger the function passed in after a certain period of time, but it seems behaving differently in a loop. For example:

for (var i = 0; i < 5; i++) {
  setTimeout(console.log(i + ', time is: ' + new Date()), 1000);
}

The console.log() seems printing out the numbers all at the same time. I do not understand why. Could some of you explain why setTimeout() does not work in this loop?

TonyW
  • 18,375
  • 42
  • 110
  • 183
  • 1
    setTimeout is not a pause, it sets a timeout from now and continues. The way to do this is a recursive function that logs itself and uses settimeout to call itself again, adding one to passed parameter (and remembering to stop recursion when your condition is met. – Regular Jo Dec 12 '14 at 22:14
  • 1
    The way you've currently written this is equivalent to doing `console.log(i + ', time is: ' + new Date()); setTimeout(undefined, 1000);` – Paul S. Dec 12 '14 at 22:16

5 Answers5

2

You're not passing the console.log to the setTimeout, you call it immediately.

Also, you need to put your i in a closure, or else all the calls will log 5.

Try this:

function makelogger(i) {
    return function () {
        console.log(i + ', time is: ' + new Date());
    }
}

for (var i = 0; i < 5; i++) {
    setTimeout(makelogger(i), 1000); // or i*1000
}
zord
  • 4,538
  • 2
  • 25
  • 30
  • fwiw it prints the 5 log messages at the same time in both chrome and firefox. – Dinesh Dec 13 '14 at 00:17
  • If you want it to log one every second, replace the `1000` to `i*1000` as I noted in that comment. – zord Dec 13 '14 at 01:08
0

If you want to execute the console function at every second, you need to do something different.

    for (var i = 1; i <= 5; i++) 
    {
      setTimeout( function() 
      {
        document.write(new Date() + "<br />");
      }, (i * 1000));
    }

This will show the time in 1 second intervals for a total of 5 times.

Ryan
  • 14,392
  • 8
  • 62
  • 102
  • this prints: 5, time is: Fri Dec 12 2014 17:24:52 GMT-0500 (EST) 5, time is: Fri Dec 12 2014 17:24:52 GMT-0500 (EST) 5, time is: Fri Dec 12 2014 17:24:52 GMT-0500 (EST) 5, time is: Fri Dec 12 2014 17:24:52 GMT-0500 (EST) 5, time is: Fri Dec 12 2014 17:24:52 GMT-0500 (EST) – TonyW Dec 12 '14 at 22:25
0

In your setTimeout the first parameter should return a function that will be executed later. So you want an expression that will be a function invocation, not the function invocation itself.

Try, as a crude example: (ttl is trials to live :)

function makelogger(ttl) {
    var msg = ttl + ', time is: ' + new Date();
    console.log(msg);

    if ( ttl > 0 ) {
      setTimeout(function(){return makelogger(ttl-1)}, 1000); 
    }
}
makelogger(5)

Here is the full MDN description

Dinesh
  • 4,437
  • 5
  • 40
  • 77
0

A solution to your problem is wrapping your function into a closure:

for (var i = 1; i <= 5; i++) 
{  
    (function(j)
    {
        setTimeout(function() 
        {
            document.write(j + " - " + new Date() + "<br />");
        }, (j * 1000));
    })(i);      
}
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
-1

You can chain your setTimeouts:

  setTimeout(function() {
    console.log(1 + ', time is: ' + new Date())
    setTimeout(function() {
        console.log(2 + ', time is: ' + new Date())
    }, 1000);
  }, 1000);

Or you can you use a function to make it good:

times = 5;
timeout(times);

function timeout(times) {
    setTimeout(function(){
        console.log(times + ', time is: ' + new Date())
        if(times > 1) {
            setTimeout(timeout(times-1), 1000);
        }
    },1000) 
}
AxelPAL
  • 1,047
  • 3
  • 12
  • 19
  • What's the purpose of the inner setTimeout? you're already doing a setTimeout upfront. (and you passed `timeout` to it incorrectly.) – Kevin B Dec 12 '14 at 22:37