JavaScript Sleep Function

  • Carnix
  • Guru
  • Guru
  • User avatar
  • Joined: Apr 28, 2004
  • Posts: 1099
  • Status: Offline

Post July 13th, 2006, 5:44 am

All,

I searched all around looking for a way to do an actual sleep function (Thread.Sleep, wait, sleep(), take your pick...) in JavaScript, and there were many posts around that use setInterval or setTimeout, there were none that actually did a real sleep.

The problem is, the setTimeout function immediately returns control to its container after it sets the timer. So, if you setTimeout(funct(),1000), and its container runs for 5 seconds longer, the last 4 seconds will see BOTH functions running at the same time. Now, arguably, this is good in some cases, perhaps even most cases as it relates to JavaScript applications. However, in an application I've been working on recently, I needed to actually sleep for a couple seconds. Literally make the script stall. The reason is, I'm using AJAX to retrieve some data, but its a very fast pull, taking almost no time at all, but we WANT the user to see the processing animation for a couple seconds (for psycological affect... its a sort of quiz).

So, here's what I did. Its actually pretty obviouls in hindsight, so I'm surprised I didn't find any one else using this technique. This is actually an except from a larger class file... Anyway, this is mostly for posterity, but comments are welcome. Oh, and I'm sure there are good reasons for not normally wanting to do this, also, I suppose if you ran this for too long, browsers would throw errors or crash... I only need it for 3-5 seconds, so this isn't a problem for me.


Code: [ Select ]
    this.Sleep = function ZZzzzZZzzzzzzZZZz(naptime){
        naptime = naptime * 1000;
        var sleeping = true;
        var now = new Date();
        var alarm;
        var startingMSeconds = now.getTime();
        alert("starting nap at timestamp: " + startingMSeconds + "\nWill sleep for: " + naptime + " ms");
        while(sleeping){
            alarm = new Date();
            alarmMSeconds = alarm.getTime();
            if(alarmMSeconds - startingMSeconds > naptime){ sleeping = false; }
        }        
        alert("Wakeup!");
    }
  1.     this.Sleep = function ZZzzzZZzzzzzzZZZz(naptime){
  2.         naptime = naptime * 1000;
  3.         var sleeping = true;
  4.         var now = new Date();
  5.         var alarm;
  6.         var startingMSeconds = now.getTime();
  7.         alert("starting nap at timestamp: " + startingMSeconds + "\nWill sleep for: " + naptime + " ms");
  8.         while(sleeping){
  9.             alarm = new Date();
  10.             alarmMSeconds = alarm.getTime();
  11.             if(alarmMSeconds - startingMSeconds > naptime){ sleeping = false; }
  12.         }        
  13.         alert("Wakeup!");
  14.     }


This is part of a class function, and since I also set var my = this; right at the top of any JS class I write, this would be called privately as my.Sleep(5), and publicly like myObject.Sleep(5) (assuming you named the object myObject, which you probably wouldn't :wink: )

.c
  • Anonymous
  • Bot
  • No Avatar
  • Joined: 25 Feb 2008
  • Posts: ?
  • Loc: Ozzuland
  • Status: Online

Post July 13th, 2006, 5:44 am

  • joebert
  • Sledgehammer
  • Genius
  • No Avatar
  • Joined: Feb 10, 2004
  • Posts: 13455
  • Loc: Florida
  • Status: Offline

Post July 13th, 2006, 6:04 am

Have you thought about using setTimeout to kill a non-async XMLHTTPRequest request ?

That's the first thing that comes to mind.
Strong with this one, the sudo is.
  • Carnix
  • Guru
  • Guru
  • User avatar
  • Joined: Apr 28, 2004
  • Posts: 1099
  • Status: Offline

Post July 13th, 2006, 8:52 am

I didn't consider that. I'm not sure that would be the best idea though, since for cross-browser compatibility, you'd have to send the request to your own domain (rather than gibberish), which, even if the URL is intentionally bad (a 404, for example), would still force an extra HTTP cycle on your server. This technique keeps it all local on the client instead.

The requirement was a script stall regardless of how long the request takes to return a response. Techically, the way I implemented it, the response is actually already recieved and cached when the Sleep method is invoked... this to avoid any timeouts and to ensure the response is actually avaialble when naptime is over should it take longer to get for some reason.

Even still, with setTimeout, you'd still have two functions running at the same time, even if one is an sync XMLHTTP request... JavaScript isn't multi-threaded, so I've found its generally best not to force it to do more than one thing at a time, if possible...

.c


.c
  • Grey
  • Novice
  • Novice
  • No Avatar
  • Joined: Jul 02, 2006
  • Posts: 34
  • Status: Offline

Post July 13th, 2006, 9:07 am

Carnix wrote:
with setTimeout, you'd still have two functions running at the same time
I wouldn't describe it that way, since as you say, JavaScript isn't multi-threaded. I'd advocate doing whatever is necessary to make use of a timeout over using a CPU-melting tight polling loop.
  • joebert
  • Sledgehammer
  • Genius
  • No Avatar
  • Joined: Feb 10, 2004
  • Posts: 13455
  • Loc: Florida
  • Status: Offline

Post July 13th, 2006, 9:28 am

That's what happens when I don't read everything in a post.

I'm not sure about the while loop.

What about starting the function with a call to a controll disabling function, then setTimeout to a controll re-enabling function ?
Strong with this one, the sudo is.
  • Carnix
  • Guru
  • Guru
  • User avatar
  • Joined: Apr 28, 2004
  • Posts: 1099
  • Status: Offline

Post July 13th, 2006, 9:53 am

Grey wrote:
Carnix wrote:
with setTimeout, you'd still have two functions running at the same time
I wouldn't describe it that way, since as you say, JavaScript isn't multi-threaded. I'd advocate doing whatever is necessary to make use of a timeout over using a CPU-melting tight polling loop.


As I said, I only have it run for a few seconds. More than likely, it would crush a browser if you let it for too long (in fact, most browsers these days will actually warn users and give them the option to stop scripts when they appear to have run away, as this would if you set it to go for more than a few seconds).


The problem with setTimeout still is that it IMMEDIATLY returns control to its container, regardless of what the function it just called is doing. So, there isn't any way to stop control in the middle of a function using setTimeout.

Now, I suppose you could do something like this:

Code: [ Select ]
function doProcess(){

//XMLHTTP processing....

showWaitDiv();
setTimeout(doNext(),5000);
return false;
}

function doNext(){
//Do whatever...
}

function showWaitDiv(){
//displays processing content
}
  1. function doProcess(){
  2. //XMLHTTP processing....
  3. showWaitDiv();
  4. setTimeout(doNext(),5000);
  5. return false;
  6. }
  7. function doNext(){
  8. //Do whatever...
  9. }
  10. function showWaitDiv(){
  11. //displays processing content
  12. }


That, however, assumes nothing else it going on, and that nothing else might go on, that could collide with the firing doNext in 5000ms, since the control will be where ever showWaitDiv() was called, not where doNext() is... This also interferes with parameter passing, although that's easy to get around by encapulation (which is how I'm doing this anyway).

Either way, your still cycling the processor for X ms... no telling how setTimeout does it internally (probably a thread.sleep embedded in the browser), which is less costly than invoking a while loop. I'll give this a try and see how it works, although I've never had much luck with setTimeouts...
.c
  • Carnix
  • Guru
  • Guru
  • User avatar
  • Joined: Apr 28, 2004
  • Posts: 1099
  • Status: Offline

Post July 13th, 2006, 10:33 am

Since the intent is for posterity, based on the comments here, I tried a setTimeout approach. While it more or less worked the same, it sort of ...felt.. better. Anyone who's developed applications knows what I mean 8)

Here's what I did. I snipped out code that was unrelated to this thread, and left out several other methods that were also not related... this is a big class nearly 400 lines (and it's not done yet...). Anyway, there you go:

Code: [ Select ]
function theClassAllChoppedUpForOzzu(){
    var my = this;
    var ProcessingImage;
    var NAP;
    //CODE SNIPPED...

    this.Initialize = function main(){
        //CODE SNIPPED...
        my.ProcessingImage = new Image();
        my.ProcessingImage.src = my.ModuleDir + "processing.gif";
        //CODE SNIPPED...
    }


    this.Submit = function ClickClickClicketyGoesTheWebMonkey(f){
        //CODE SNIPPED...

            my.ToggleProcessorImage(true);
            my.HTTP_Request(my.DisplayQuizResults);

        //CODE SNIPPED...
    }


    this.HTTP_Request = function sendUpHTTPRequestLikeTheSeverNeedsAnotherOne(RESPONSE_HANDLER){
        //CODE SNIPPED...
        try{
            httpRequestObj.onreadystatechange = RESPONSE_HANDLER;
            //CODE SNIPPED...
        }
        catch(err){
            //CODE SNIPPED...
        }
    }

    this.DisplayQuizResults = function doSomethingWithTheServersReply(){
        try{
            if(httpRequestObj.readyState == 4){
                //CODE SNIPPED...
                my.NAP = setTimeout(my.Sleep,2000);
            }
        }
        catch(err){
        //CODE SNIPPED...
        }
    }

    this.ShowResults = function okReallyThisWillShowTheResults(){
        my.ToggleProcessorImage(false);
        //CODE SNIPPED...
    }

    this.Sleep = function ZZzzzZZzzzzzzZZZz(){
        my.ShowResults();
        return false;
    }
    
    this.ToggleProcessorImage = function showTheFunnySpinnerThing(flag){
        //CODE SNIPPED...
    }
}
  1. function theClassAllChoppedUpForOzzu(){
  2.     var my = this;
  3.     var ProcessingImage;
  4.     var NAP;
  5.     //CODE SNIPPED...
  6.     this.Initialize = function main(){
  7.         //CODE SNIPPED...
  8.         my.ProcessingImage = new Image();
  9.         my.ProcessingImage.src = my.ModuleDir + "processing.gif";
  10.         //CODE SNIPPED...
  11.     }
  12.     this.Submit = function ClickClickClicketyGoesTheWebMonkey(f){
  13.         //CODE SNIPPED...
  14.             my.ToggleProcessorImage(true);
  15.             my.HTTP_Request(my.DisplayQuizResults);
  16.         //CODE SNIPPED...
  17.     }
  18.     this.HTTP_Request = function sendUpHTTPRequestLikeTheSeverNeedsAnotherOne(RESPONSE_HANDLER){
  19.         //CODE SNIPPED...
  20.         try{
  21.             httpRequestObj.onreadystatechange = RESPONSE_HANDLER;
  22.             //CODE SNIPPED...
  23.         }
  24.         catch(err){
  25.             //CODE SNIPPED...
  26.         }
  27.     }
  28.     this.DisplayQuizResults = function doSomethingWithTheServersReply(){
  29.         try{
  30.             if(httpRequestObj.readyState == 4){
  31.                 //CODE SNIPPED...
  32.                 my.NAP = setTimeout(my.Sleep,2000);
  33.             }
  34.         }
  35.         catch(err){
  36.         //CODE SNIPPED...
  37.         }
  38.     }
  39.     this.ShowResults = function okReallyThisWillShowTheResults(){
  40.         my.ToggleProcessorImage(false);
  41.         //CODE SNIPPED...
  42.     }
  43.     this.Sleep = function ZZzzzZZzzzzzzZZZz(){
  44.         my.ShowResults();
  45.         return false;
  46.     }
  47.     
  48.     this.ToggleProcessorImage = function showTheFunnySpinnerThing(flag){
  49.         //CODE SNIPPED...
  50.     }
  51. }


(Oh yeah, the function names... heh, the class name itself isn't that... but the private function names are... since they are more or less irrelevant, I like getting creative... I use conventional names to reference them as methods though...)

.c
  • joebert
  • Sledgehammer
  • Genius
  • No Avatar
  • Joined: Feb 10, 2004
  • Posts: 13455
  • Loc: Florida
  • Status: Offline

Post July 13th, 2006, 10:52 am

The while loop sure does look alot easier to work with than setTimeout when it's all in one place like that. Beats the hell out of "just trust me" if you know what I mean.

Nice stuff carnix ! 8)
Strong with this one, the sudo is.
  • Carnix
  • Guru
  • Guru
  • User avatar
  • Joined: Apr 28, 2004
  • Posts: 1099
  • Status: Offline

Post July 13th, 2006, 11:16 am

joebert wrote:
The while loop sure does look alot easier to work with than setTimeout when it's all in one place like that. Beats the hell out of "just trust me" if you know what I mean.



Yup... my thoughts exactly. But... sometimes short,sweet code isn't the most efficient. The more I think about it... yes, I had to define two methods to do what I was doing with only one before, using setTimeout in his way uses a native function, and lets the actual browser do the heavy work rather than force-feeding a stall. That is, the waiting isn't being done via JavaScript itself, its being handled somewhere above the script in the browser's memory space, then the next step is called a couple seconds later. Its much less CPU intensive (and, I noticed, the animation ran better... hence the 'feeling' :wink: )

Besides, I'm a big proponent of using native software and tools rather than trying to force other tools to work like a native one already does (Apache/mySQL/PHP on Windows, for example.... ASP on Unix.... ColdFusion anywhere other than the trash where it belongs.... :lol: ).


So, world, there you go. An actual discussion on Javascript sleep functions that has an alternative to using setTimeout, even if it wasn't the final solution. Enjoy! =]

.c
  • acklenx
  • Born
  • Born
  • No Avatar
  • Joined: Jun 08, 2007
  • Posts: 1
  • Status: Offline

Post June 8th, 2007, 10:10 am

Code: [ Select ]
/**
*@description pause( iMilliseconds ) Cause the single Javascript thread to hald/pause/sleep/wait for a specified period of time, by opening in modalDialog window (IE only) that modally locks the browser until it returns. This modal dialog is not opened to any page, but uses the Javascript: protocol to execute a javascript setTimeout. In this modal context the setTimeout, has the desired affect of preventing any other script execution. The sole purpose of the timeout execution script is to close the modal dialog which will return control/unluck the browser. The intention was to find a way to allow the UI to be updated and rendered in the middle of function/method without the need to split the method up, remove nested calls, or use closures. Used in this fashion to update the UI, a 0 (zero) is usually passed (or optionally omitted altogether) so that the only delay is for the UI to render.
*@version Note Please be aware that the user interface WILL update its rendering (if you've made and DOM/CSS/Text changes they will appear) and this may significantly slow down program execution if looping.
*@keywords pause sleep wait halt javascript show modal dialog set timeout multi-threaded single thread
*@version 1.2
* @param {Object} iMilliseconds [optional] the number of milliseconds the code will pause before returning - If no value is passed the code will returned immediately (as if a 0 were passed)
* @return undefined there is no return value from this function
*/
function pause( iMilliseconds )
{
  var sDialogScript = 'window.setTimeout( function () { window.close(); }, ' + iMilliseconds + ');';
  window.showModalDialog('javascript:document.writeln ("<script>' + sDialogScript + '<' + '/script>")');
}
  1. /**
  2. *@description pause( iMilliseconds ) Cause the single Javascript thread to hald/pause/sleep/wait for a specified period of time, by opening in modalDialog window (IE only) that modally locks the browser until it returns. This modal dialog is not opened to any page, but uses the Javascript: protocol to execute a javascript setTimeout. In this modal context the setTimeout, has the desired affect of preventing any other script execution. The sole purpose of the timeout execution script is to close the modal dialog which will return control/unluck the browser. The intention was to find a way to allow the UI to be updated and rendered in the middle of function/method without the need to split the method up, remove nested calls, or use closures. Used in this fashion to update the UI, a 0 (zero) is usually passed (or optionally omitted altogether) so that the only delay is for the UI to render.
  3. *@version Note Please be aware that the user interface WILL update its rendering (if you've made and DOM/CSS/Text changes they will appear) and this may significantly slow down program execution if looping.
  4. *@keywords pause sleep wait halt javascript show modal dialog set timeout multi-threaded single thread
  5. *@version 1.2
  6. * @param {Object} iMilliseconds [optional] the number of milliseconds the code will pause before returning - If no value is passed the code will returned immediately (as if a 0 were passed)
  7. * @return undefined there is no return value from this function
  8. */
  9. function pause( iMilliseconds )
  10. {
  11.   var sDialogScript = 'window.setTimeout( function () { window.close(); }, ' + iMilliseconds + ');';
  12.   window.showModalDialog('javascript:document.writeln ("<script>' + sDialogScript + '<' + '/script>")');
  13. }
  • Steve Waring
  • Born
  • Born
  • User avatar
  • Joined: Sep 08, 2007
  • Posts: 1
  • Loc: Brierley Hill, West Midlands, UK
  • Status: Offline

Post September 8th, 2007, 6:23 am

That last method is superb. Concise and elegant. At last a way to render changes part way through a script, and a proper sleep too.

Thank you. :D
  • buggalugs
  • Born
  • Born
  • No Avatar
  • Joined: Dec 12, 2007
  • Posts: 1
  • Status: Offline

Post December 12th, 2007, 8:58 pm

Too bad it doesn't work in IE7. Face it, there is no sleep function in Javascript.
  • camperjohn
  • Guru
  • Guru
  • User avatar
  • Joined: Nov 28, 2004
  • Posts: 1127
  • Loc: San Diego
  • Status: Offline

Post December 13th, 2007, 11:30 am

Why not do the sleep on the server in PHP.

This allows it to be browser independant. If the issue is you want the results to appear non-right-away, then maybe it will work.
Upload video and picture galleries at http://www.bodydot.com?post+upload+video+picture+gallery
  • Mike Duskis
  • Born
  • Born
  • No Avatar
  • Joined: Sep 30, 2008
  • Posts: 2
  • Status: Offline

Post September 30th, 2008, 4:10 pm

Excellent concept, Carnix. I think we can implement it with less code:
Code: [ Select ]
/**
* Delay for a number of milliseconds
*/
function sleep(delay)
{
    var start = new Date().getTime();
    while (new Date().getTime() < start + delay);
}
  1. /**
  2. * Delay for a number of milliseconds
  3. */
  4. function sleep(delay)
  5. {
  6.     var start = new Date().getTime();
  7.     while (new Date().getTime() < start + delay);
  8. }
  • joebert
  • Sledgehammer
  • Genius
  • No Avatar
  • Joined: Feb 10, 2004
  • Posts: 13455
  • Loc: Florida
  • Status: Offline

Post September 30th, 2008, 5:25 pm

I still can't figure out what use a sleep function for JS is. :scratchhead:
Strong with this one, the sudo is.
  • Anonymous
  • Bot
  • No Avatar
  • Joined: 25 Feb 2008
  • Posts: ?
  • Loc: Ozzuland
  • Status: Online

Post September 30th, 2008, 5:25 pm

Post Information

  • Total Posts in this topic: 26 posts
  • Users browsing this forum: No registered users and 134 guests
  • You cannot post new topics in this forum
  • You cannot reply to topics in this forum
  • You cannot edit your posts in this forum
  • You cannot delete your posts in this forum
  • You cannot post attachments in this forum
 
 

© 2011 Unmelted, LLC. Ozzu® is a registered trademark of Unmelted, LLC.