Tuesday, December 13, 2005

Javascript sleep() or wait()

While thinking on a solution for handling javascript "alerts" in Sahi, it suddenly occured to me that a sleep() or wait() method can be implemented in javascript with the help of a synchronous XMLHttp request to the server.
It goes like:

<script>
function sahiIsIE(){
var browser = navigator.appName;
return browser == "Microsoft Internet Explorer";
}

function sahiCreateRequestObject(){
var obj;
if(sahiIsIE()){
obj = new ActiveXObject("Microsoft.XMLHTTP");
}else{
obj = new XMLHttpRequest();
}
return obj;
}

function sahiSendToServer(url){
try{
var http = sahiCreateRequestObject();
var url = url;
http.open("GET", url, false);
http.send(null);
return http.responseText;
}catch(ex){throw ex;}
}

function sleep(ms){
sahiSendToServer("http://localhost:9999/dyn/sleep?ms="+ms);
}

var start = new Date();
sleep(1000);
alert((new Date()) - start);

</script>

The url http://localhost:9999/dyn/sleep?ms=1000 does a Thread.sleep(1000);

Of course there is the network delay which makes the time out slightly greater than 1000 ms;

[Dec 20 2007] NOTE: This method can give you a way to invoke a sleep on the browser, but it will also kind of freeze the browser which may not be what you want. I solved this problem in a different way for Sahi. (javascript-sleep-or-wait-in-sahi.html)

16 comments:

Anonymous said...

What's wrong with the built in setTimeout function?

setTimeout(functionToCall, 1000)

Anonymous said...

I can't believe saw your article on Planet ThoughtWork. ThoughtWork ... didn't they create Selenium ?
Why an other Web test tools ???

Anonymous said...

There's nothing wrong with setTimeout(). In fact, it's great 99% of the time. But every once in a long while, you write something where your calling function absolutely, positively wants to wait without exiting its current thread. I'm going to give this a go for my current problem, it's pretty ingenious.

Anonymous said...

Rats. This causes firefox to completely lock up until the call returns, and it won't execute any scripts on different thread. So much for that idea -- hope it helps in other contexts.

Anonymous said...

Why people always come with setTimeout.
setTimeout is not a sleep function!!

JavaScript lacks the sleep function and that's what's totally wrong about javascript.

the 'showModalDialog' 'hack' works for IE6. But in IE7 it's not working anymore.

Anonymous said...

Good design!
http://uuksmbxh.com/bewb/ihha.html | http://epugejhx.com/ftog/kgna.html

Unknown said...

Doesn't this multiply my network traffic by however many seconds long my requests are taking?

Unknown said...

Doesn't this multiply my network traffic by however many second my requests are taking?

Anonymous said...

Nice lateral thinking, this is the closest to an actual solution to this problem that I have seen, and I have been searching for quite a while, but it does seem that necessity is the mother of desperation in this case.

The point of this exercise isn't to stop the current thread
- it's to pump processor cycles to any other threads that are currently running, especially to allow a screen refresh to run mid-process, to keep the user informed of progress during a long function.

Just getting the current thread to thrash the whole processor for X milliseconds doesn't really achieve anything.

Using setTimeout requires that the current thread complete, then a new one starts after a delay, which means you have to split your function up into discrete processes - what we really need is a free-standing function that could be added inline to any block of code to share the processor on the fly.

A method like document.refresh(), (suggestions anyone?) would be an ideal solution to this problem, but it (amazingly) doesn't seem to exist anywhere in the public arena.

If we can work this one out here, it will be the first time the internet has been offered this solution. c'mon, where is document.refresh()?

- Alex McCombie

Anonymous said...

javascript:location.reload(true); will refresh the page

Anonymous said...

Has this been solved?

Here is a synchronous browser doevents that works for the delay needed for IE's appendchild.

function doBrowserEvents(msecs)
{
var i=0;
var j5timerXH = initXmlHttpTimer(); // just creates an XMLHttp obj
var j5UTC = new Date();
while ((new Date()) - j5UTC < msecs)
{
i++;
j5timerXH.open("GET","/doesnotexist",false);
j5timerXH.send(null);
}
return i;
}

Unknown said...

Wow, yes, i agree with him...
its a brilliant way of emulating sleep in js.
this will help a lot..

Anonymous said...

function sleep(numberMillis){
var now = new Date();
var exitTime = now.getTime() + numberMillis;
while (true){
now = new Date();
if (now.getTime() > exitTime) return;
}
};

David said...

It's an ugly solution.
You design your scripts so that setTimeout can be used.
If someone showed me this in a code review, I'd squint at them and shake my head.

Anonymous said...

This is an absolutely terrible idea.

You are seriously going to tie up a httpd connection for a whole second doing *nothing*?!

Madness. You have clearly never written a web application intended to even remotely scale. You should be a PHP programmer, but I suspect you probably are already ;)

V. Narayan Raman said...

The last comment was funny. Why target PHP guys :)

Yes this wait cannot be used for scalable apps. It was meant more for tools like Sahi which use javascript but which needed a wait between steps. But this technique is not useful as far as I have used it. It locks the browser and is hence useless. The easier and better way when writing web apps will definitely be to split the code into functions and use fn1(); setTimeout('fn2()', 1000); etc. to attain that functionality. For others who are looking to write a debugger or testing tool in javascript, you may want to look at how I solved this problem for Sahi. It is mentioned at the end of the post.