To sleep with javascript
By Andrew Smith
All proper programming languages I can think of have a real simple function – sleep(). It suspends the execution of your program for a time. This is what I wanted to do. Having no choice but to use javascript in this case, I went around looking for what the sleep() function is called in this dreadful language.
Turns out there is none. There is only setTimeout() and setInterval(). Either will call a function after a time, but in between your code will continue to execute.
All I could find on the internet is a bunch of solutions to this problem involving an infinite loop. That, for I hope obvious reasons, was not acceptable for me.
I considered using `yield` but that doesn’t work for some reason in my version of the current firefox trunk. I did the javascript version thing, but then none of the javascript I had (yield or not) would work at all.
So I grumbled for a couple of hours and finally figured out a solution so my stuff still works as I want it, and all that’s lost is readability. I’ll share this beast with you all in case you ever run into the same problem.
This is what I wanted done in the first place, overly simplfied (lack of whitespace courtesy of wordpress):
function wish(i, j)
{
var k = i + j;
for(var m = 0; m < 10; m++)
{
// start doing something outside of my control
sleep(5000); // sleep for 5 seconds
// check the results of the something
alert(k + “, ” + m + results);
}
}
Like I said, it’s overly simplified. There’s no need to bring 3D and benchmarks into this example.
Since setInterval() is all I have to work with, that’s what I’ll use. The tricks to address my concerns are:
- Make a global function that will take the (i, j) parameters and have it call another function (real()) that doesn’t take any parameters
- Copy the parameters to wish() into glabal variables
- Where the sleep() would be have a setInterval(‘real()’, 5000) instead
- Copy all the local variables in real() to global variables before the setInterval()
- Add a condition so real() will know whether it should continue from where it left off or start from the beginning.
A lot of work, but the other option is to not do it at all.. Here’s what it now looks like:
var gI;
var gJ;
function wish(i, j)
{
gI = i;
gJ = j;
real();
}
var gK;
var gM = 0;
var didSleep = false;
function real()
{
if (didSleep)
{
// check the results of the something
alert(gK + “, ” + (gM – 1) + results);
}
else
{
gK = gI + gJ;
}
for(m = gM; m < 10; m++)
{
// start doing something outside of my control
gK = k;
gM = m + 1;
didSleep = true;
setInterval(“real()”, 5000);
return;
}
}
That’s pretty disgusting. I’d blame the people who came up with javascript if it wasn’t for the fact that javascript was never designed to be a proper language. Javascript was made for people one level above HTML, which is far, far from real programming and it served those people well.
Instead I blame the people responsible for the javascript hype. Both the fanboys who don’t know any better but their strength is in numbers; and the programmers who sell their time/ideas by proclaiming that AJAX is the only way to go. I even blame google a little for making the two useful javascript applications in the world.
I’ll say it again – disgusting.
March 22nd, 2008 at 11:00
I should add that if you want to use generators to emulate parallel flows of control, you can do so on top of yield. Someone who doesn’t understand closures is unlikely to have a good time implementing it from scratch, but happily you don’t have to: http://www.neilmix.com/2007/02/07/threading-in-javascript-17/
March 22nd, 2008 at 11:10
[Think this bounced off because of some angle brackets in my code snippet; hard to tell without preview.]
I think the designer of JavaScript would tell you otherwise about the design goals; it’s not hard to find very experienced language designers and developers who will praise JavaScript’s use of delegation and first-class functions as powerful tools, but if you try to write C in JavaScript, you’ll hurt. Just as if you tried to write Lisp in C, or Fortran in shell. (Said designer used to be a co-worker of yours; you could have asked him about it!)
I don’t know why you need globals, though; can’t you just pass a closure to setInterval?
(The timer and theoretical sleep functions in question belong to the DOM, not to the language, as many languages have a distinction between runtime and language. JavaScript’s run-to-completion semantics are important for coherence on the web, and mean that you can’t have any response to script action on a page when a putative sleep(5000) was sleeping. It would be like putting a sleep(5000) in a GTK event handler in your beloved C: you’d lock up the app for 5 seconds at a time. Non-web embeddings can and do have sleep() functions in them; the JS shell in the mozilla tree is such an example. Not that you seem to care about learning what JavaScript is actually good for, or how it can be used successfully, since you have already made up your mind permanently after that first weekend of naive hacking, but other people might read your post who aren’t as closed-minded. JS definitely has its flaws, and the DOM in which its embedded even more so, as anyone with non-trivial experience with it will tell you readily. + as string and integer operator both? with? the value of delete expressions? The list definitely goes on, but there’s no language without a similar list of flaws.)
function wish(i, j)
{
var k = i + j;
var m = 0, max = 10;
function heartbeat() {
alert(k + “, ” + m + results);
if (++m greaterthanorequalto 10)
cancelTimeout(timeout);
}
var timeout = setInterval(heartbeat, 5000);
}
Untested, but a pattern that’s widely used, and doesn’t involve global variables or other such mess. Not knowing how to use closures in JS is like not knowing how to use pointers in C: I don’t think you would think very highly of someone who said “C sucks! it’s so ugly to manage state between caller and callee!” but didn’t bother using pointers to do it.
March 22nd, 2008 at 17:28
Ah, so a sleep() would block everything the browser? I thought the reason there’s no sleep() might be something like that.
June 26th, 2008 at 13:27
This article does nothing other than to show your lack of JavaScript knowledge. I’m not sure why you assumed that something couldn’t be done just because you couldn’t figure it out. JavaScript is very powerful and can emulate sleep() type behavior trivially. To see this behavior used extremely well, see: http://developer.yahoo.com/yui/yuitest/
November 10th, 2009 at 0:11
I have searched/googled quite a few webpages on javascript sleep/wait… and there is NO answer if you want javascript to “RUN, DELAY, RUN”… what most people got was either, “RUN, RUN(useless stuff), RUN” or “RUN, RUN + delayed RUN”….
So I ate some burgers and got thinking:::
here is a solution that works… but you have to chop up your running codes…:::
replace <.. with < to run..
//…………………………………..
//example1:
DISPLAY
//javascript sleep by “therealdealsince1982″; copyrighted 2009
//setInterval
var i = 0;
function run() {
//pieces of codes to run
if (i==0){document.getElementById(“id1″).innerHTML= “code segment “+ i +” is ran”; }
if (i==1){document.getElementById(“id1″).innerHTML= “code segment “+ i +” is ran”; }
if (i==2){document.getElementById(“id1″).innerHTML= “code segment “+ i +” is ran”; }
if (i >2){document.getElementById(“id1″).innerHTML= “code segment “+ i +” is ran”; }
if (i==5){document.getElementById(“id1″).innerHTML= “all code segment finished running”; clearInterval(t); } //end interval, stops run
i++; //segment of code finished running, next…
}
t=setInterval(“run()”,1000);
//………………………………
//example2:
DISPLAY
//javascript sleep by “therealdealsince1982″; copyrighted 2009
//setTimeout
var i = 0;
function flow() {
run(i);
i++; //code segment finished running, increment i; can put elsewhere
sleep(1000);
if (i==5) {clearTimeout(t);} //stops flow, must be after sleep()
}
function run(segment) {
//pieces of codes to run, can use switch statement
if (segment==0){document.getElementById(“id1″).innerHTML= “code segment “+ segment +” is ran”; }
if (segment==1){document.getElementById(“id1″).innerHTML= “code segment “+ segment +” is ran”; }
if (segment==2){document.getElementById(“id1″).innerHTML= “code segment “+ segment +” is ran”; }
if (segment >2){document.getElementById(“id1″).innerHTML= “code segment “+ segment +” is ran”; }
}
function sleep(dur) {t=setTimeout(“flow()”,dur);} //starts flow control again after dur
flow(); //starts flow
//……………………………….
//example3:
DISPLAY
//javascript sleep by “therealdealsince1982″; copyrighted 2009
//setTimeout, switch
var i = 0;
function flow() {
switch(i)
{
case 0:
run(i);
sleep(1000);
break;
case 1:
run(i);
sleep(2000);
break;
case 5:
run(i);
clearTimeout(t); //stops flow
break;
default:
run(i);
sleep(3000);
break;
}
}
function run(segment) {
//pieces of codes to run, can use switch statement
if (segment==0){document.getElementById(“id1″).innerHTML= “code segment “+ segment +” is ran”; }
if (segment==1){document.getElementById(“id1″).innerHTML= “code segment “+ segment +” is ran”; }
if (segment==2){document.getElementById(“id1″).innerHTML= “code segment “+ segment +” is ran”; }
if (segment >2){document.getElementById(“id1″).innerHTML= “code segment “+ segment +” is ran”; }
i++; //current segment of code finished running, next…
}
function sleep(dur) {t=setTimeout(“flow()”,dur);} //starts flow control again after dur
flow(); //starts flow control for first time…