dlyk1988
dlyk1988

Reputation: 437

Node.js setTimeout() behaviour

I want a piece of code to repeat 100 times with 1 sec of delay in between. This is my code:

for(var i = 0; i < 100; i++){
  setTimeout(function(){
    //do stuff
  },1000);
}

While this seems correct to me it is not. Instead of running "do stuff" 100 times and waiting 1 sec in between what it does is wait 1 sec and then run "do stuff" 100 times with no delay.

Anybody has any idea about this?

Upvotes: 1

Views: 2182

Answers (4)

wlh
wlh

Reputation: 3515

I prefer the recursive function. Call the function initially with the value of counter = 0, and then within the function check to see that counter is less than 100. If so, do your stuff, then call setTimeout with another call to doStuff but with a value of counter + 1. The function will run exactly 100 times, once per second, then quit :

const doStuff = counter => {
    if (counter < 100) {
        // do some stuff
        setTimeout(()=>doStuff(counter + 1), 1000)
    }
    return;
}
doStuff(0)

Upvotes: 0

Mauno V&#228;h&#228;
Mauno V&#228;h&#228;

Reputation: 9788

You can accomplish it by using setInterval().

It calls function of our choice as long as clearTimeout is called to a variable timer which stores it.

See example below with comments: (and remember to open your developer console (in chrome right click -> inspect element -> console) to view console.log).

// Total count we have called doStuff()
var count = 0;

/**
 * Method for calling doStuff() 100 times
 *
 */
var timer = setInterval(function() {

    // If count increased by one is smaller than 100, keep running and return
    if(count++ < 100) {
        return doStuff();
    }

    // mission complete, clear timeout
    clearTimeout(timer);

}, 1000); // One second in milliseconds

/**
 * Method for doing stuff
 *
 */
function doStuff() {
   console.log("doing stuff");
}

Here is also: jsfiddle example

As a bonus: Your original method won't work because you are basically assigning 100 setTimeout calls as fast as possible. So instead of them running with one second gaps. They will run as fast as the for loop is placing them to queue, starting after 1000 milliseconds of current time.

For instance, following code shows timestamps when your approach is used:

for(var i = 0; i < 100; i++){
  setTimeout(function(){

    // Current time in milliseconds
    console.log(new Date().getTime()); 

  },1000);
}

It will output something like (milliseconds):

1404911593267 (14 times called with this timestamp...)
1404911593268 (10 times called with this timestamp...)
1404911593269 (12 times called with this timestamp...)
1404911593270 (15 times called with this timestamp...)
1404911593271 (12 times called with this timestamp...)

You can see the behaviour also in: js fiddle

Upvotes: 2

shennan
shennan

Reputation: 11656

Now that you appreciate that the for loop is iterating in a matter of milliseconds, another way to do it would be to simply adjust the setTimeout delay according to the count.

for(var i = 0; i < 100; i++){

  setTimeout(function(){

    //do stuff

  }, i * 1000);

}

For many use-cases, this could be seen as bad. But in particular circumstances where you know that you definitely want to run code x number of times after y number of seconds, it could be useful.

It's also worth noting there are some that believe using setInterval is bad practise.

Upvotes: 0

DrakaSAN
DrakaSAN

Reputation: 7853

You need to use callback, node.js is asynchronous:

function call_1000times(callback) {
var i = 0,

function do_stuff() {
    //do stuff
    if (i < 1000) {
        i = i + 1;
        do_stuff();
    } else {
        callback(list);
    }
}
do_stuff();
}

Or, more cleaner:

setInterval(function () {
    //do stuff
}, 1000);

Upvotes: 0

Related Questions