views:

366

answers:

5

I thought I would try and be clever and create a Wait function of my own (I realise there are other ways to do this). So I wrote:

var interval_id;
var countdowntimer = 0;

function Wait(wait_interval) {
  countdowntimer = wait_interval;

  interval_id = setInterval(function() {
    --countdowntimer <=0 ? clearInterval(interval_id) : null;
  }, 1000);

  do {} while (countdowntimer >= 0);
}

// Wait a bit: 5 secs
Wait(5);

This all works, except for the infinite looping. Upon inspection, if I take the While loop out, the anonymous function is entered 5 times, as expected. So clearly the global variable countdowntimer is decremented.

However, if I check the value of countdowntimer, in the While loop, it never goes down. This is despite the fact that the anonymous function is being called whilst in the While loop!

Clearly, somehow, there are two values of countdowntimer floating around, but why?

EDIT

Ok, so I understand (now) that Javascript is single threaded. And that - sort of - answers my question. But, at which point in the processing of this single thread, does the so called asynchronous call using setInterval actually happen? Is it just between function calls? Surely not, what about functions that take a long time to execute?

+2  A: 
T.J. Crowder
LOL! Do you call this a minimalistic reworking? How about `setTimeout,function(){alert("Done Waiting");}, 5000);` ;)
Sean Kinsey
function Wait(interval, callback) { return setTimeout(callback, interval * 1000); }:P
Pablo Cabrera
@Sean: What I meant by "minimalist" was "changing as little as possible to make it functional" (e.g., by way of explanation), not "making a minimal thing". he already *has* the minimal thing: `setInterval` and `setTimeout` themselves! :-)
T.J. Crowder
I'll accept your answer, because you gave the most detailed one.
Jonathan Swift
+2  A: 

Most Javascript implementation are single threaded, so when it is executing the while loop, it doesn't let anything else execute, so the interval never runs while the while is running, thus making an infinite loop.

There are many similar attempts to create a sleep/wait/pause function in javascript, but since most implementations are single threaded, it simply doesn't let you do anything else while sleeping(!).

The alternative way to make a delay is to write timeouts. They can postpone an execution of a chunk of code, but you have to break it in many functions. You can always inline functions so it makes it easier to follow (and to share variables within the same execution context).

There are also some libraries that adds some syntatic suggar to javascript making this more readable.

EDIT: There's an excelent blog post by John Resig himself about How javascript timers work. He pretty much explains it in details. Hope it helps.

Pablo Cabrera
A: 

Instead of using a global countdowntimer variable, why not just change the millisecond attribute on setInterval instead? Something like:

var waitId;

function Wait(waitSeconds)
{
    waitId= setInterval(function(){clearInterval(waitId);}, waitSeconds * 1000);
}
sohtimsso1970
Because I would use setTimeout instead. The point is that I want to wait synchronously not asynchronously.
Jonathan Swift
@Jonathan: You can't.
T.J. Crowder
+1  A: 

Actually, its pretty much guaranteed that the interval function will never run while the loop does as javascript is single-threaded.

There is a reason why no-one has made Wait before (and so many have tried); it simply cannot be done.

You will have to resort to braking up your function into bits and schedule these using setTimeout or setInterval.

//first part
...
setTimeout(function(){
    //next part
}, 5000/*ms*/);

Depending on your needs this could (should) be implemented as a state machine.

Sean Kinsey
A: 

Adding to what others have already said, and in response to your edit, I think this will clear things up: http://ejohn.org/blog/how-javascript-timers-work/. That's when your callback will fire.

Matt Ball