Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Page 1 of 2 12 LastLast
Results 1 to 15 of 30
  1. #1
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,642
    Thanks
    0
    Thanked 649 Times in 639 Posts

    JavaScript sleep function

    The following code allows you to put delays into your JavaScript provided that the process you are running is contained entirely within the one function and you don't try to put a delay into the middle of a loop.

    The example displays one line of text then waits five seconds then displays the second line then waits a further three seconds and then displays the third line - all in the same div over the top of one another.

    Code:
    <html>
    <head>
    </head>
    <body>
    <div id="text"></div>
    <script type="text/javascript">
    Function.prototype.allowSleep = function(n) {
      var i, f;
      if (!/^[$\w]+$/.test(n)) return;
      i = 0;
      f = this.toString().replace(/sleep\((.*?)\);/g , function(f,t) {i++; return n+".f"+i+" = function() {"+n+".func"+i+"();};\nsleep("+t+","+n+".f"+i+");\n"+(i==1?"":"}\n")+n+".func" + i +" = function() {";});
      eval(n+'='+f+'\n}');
    }
    sleep = function(t,f) {
      if (f === undefined) return;
      setTimeout(f,t);
    }
     
    afunc = function() {
      document.getElementById('text').innerHTML = 'first message';
      sleep(5000);
      document.getElementById('text').innerHTML = 'message the second';
      sleep(3000);
      document.getElementById('text').innerHTML = 'last message';
    }
    afunc.allowSleep('afunc'); // comment out to disable sleep
    afunc();
    </script>
    </body>
    </html>
    Note that any code following the end of the function will not be delayed by the sleep. Inserting the sleep into the middle of a loop will stop the code running at all as the code after the sleep is moved to a separate function.

    I don't have solutions for either of these - if you do then please share.

    I can't see a way to avoid the eval in this code either since the function needs to be converted to a string before it can be amended and the only way that it can easily be converted back to a function is using eval. The first regular expression test() ensures that the only variable part of what is constructed has to be valid for it to run.
    Last edited by felgall; 06-02-2012 at 03:50 AM.
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • #2
    Supreme Master coder! Philip M's Avatar
    Join Date
    Jun 2002
    Location
    London, England
    Posts
    18,079
    Thanks
    203
    Thanked 2,542 Times in 2,520 Posts
    Perhaps I am a little dim this morning, but I do not see how that code differs in its result from:-

    Code:
    <div id = "message"></div>
    
    <script type = "text/javascript">
    
    setTimeout(m1,2000);
    
    function m1() {
    document.getElementById('message').innerHTML = 'First message';
    setTimeout(m2,2000);
    }
    function m2() {
    document.getElementById('message').innerHTML = 'Message the second';
    setTimeout(m3,2000);
    }
    function m3() {
    document.getElementById('message').innerHTML = 'This is the last message';
    }
    
    </script>

    All the code given in this post has been tested and is intended to address the question asked.
    Unless stated otherwise it is not just a demonstration.

  • #3
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,642
    Thanks
    0
    Thanked 649 Times in 639 Posts
    Quote Originally Posted by Philip M View Post
    Perhaps I am a little dim this morning, but I do not see how that code differs in its result
    It differs with respect to function scope. With my version everything inside the function shares the same local scope - with your version you have three separate functions and any variables defined locally in one would not be able to be accessed in the others. The JavaScript that my code generates nests the second and third functions inside the first in order that they can share the same scope.

    Consider this slight change (using an alert just for the purpose of demonstrating the difference).

    Code:
    afunc = function() {
      var a = "end of function";
      document.getElementById('text').innerHTML = 'first message';
      sleep(5000);
      document.getElementById('text').innerHTML = 'message the second';
      sleep(3000);
      document.getElementById('text').innerHTML = 'last message';
      alert(a);
    }
    Plus it is really easy to be able to temporarily add a delay into the middle of any function using sleep() rather than having to rewrite the function into two and then have to change it back afterwards when the delay is no longer needed. You can take ANY function and stick sleep() anywhere in the function except inside a loop and have it working straight away without having to do any rewrite of the other code in the function itself.

    Anyway there are lots of people familiar with being able to use sleep() to pause their processing (based on how it works in other languages) who don't know how to construct an equivalent using setTimeout - particularly where the before and after code needs to be able to share variables that are in local scope.

    Also with slight changes the same code can be used to produce modal lightbox scripts with the code that the lightbox submits to being part of the same function as the before code - just as they would be familiar with using alert, confirm and prompt.

    Most people using JavaScript do not know it anywhere as well as you do and so would find it far easier using sleep() than setTimeout() when they want one or more delays in the middle of their functions. Only those more knowledgeable with JavaScript are aware of how to achieve the same result using setTimeout (which is after all what my allowSleep method rewrites the function to use).

    Basically my code allows a delay to be added into the middle of any function by adding a call eo sleep() that specifies how long the delay should be and then using allowSleep() to rewrite the function for you into a version that uses setTimeout calls - so as to save you from having to do the rewrite yourself. Why rewrite function code when JavaScript can do it for you?
    Last edited by felgall; 06-02-2012 at 08:43 AM.
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • #4
    Supreme Master coder! Philip M's Avatar
    Join Date
    Jun 2002
    Location
    London, England
    Posts
    18,079
    Thanks
    203
    Thanked 2,542 Times in 2,520 Posts
    Quote Originally Posted by felgall View Post
    It differs with respect to function scope. With my version everything inside the function shares the same local scope - with your version you have three separate functions and any variables defined locally in one would not be able to be accessed in the others.
    Well, yes, but it is not too hard to make the variables within a function global were that required, either by declaring them outside the function or by omitting the var keyword.

    To forestall your objection, I don't see why global variables should be avoided in less complicated applications. Any risk of duplication if another script is added is minimised if the variables are given descriptive names (i.e., not a,b and c) such as "customerName" or "orderQuantity". I myself have never encountered this duplication problem in real life.

    Your sleep() function uses eval() which in the past you have condemned mercilessly and described as evil.
    E.G: http://www.codingforums.com/showthread.php?t=249546 Post#3.
    Surely it is still evil even if you cannot find a way of avoiding it?


    If you want a really horrible sleep() function - which works - you could try this:-


    Code:
    <input type = "text" name = "txt1" onblur = "snooze(5)">
    
    <script type = "text/javascript">
    
    // charges CPU 100%
    
    function snooze(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 ("Wake Up!");
    }
    
    </script>
    Last edited by Philip M; 06-02-2012 at 09:10 AM.

    All the code given in this post has been tested and is intended to address the question asked.
    Unless stated otherwise it is not just a demonstration.

  • #5
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,642
    Thanks
    0
    Thanked 649 Times in 639 Posts
    Quote Originally Posted by Philip M View Post
    or by omitting the var keyword.
    If you do that then strict JavaScript will refuse to run because it requires that all variables be declared before you can use them.

    Anyway my code ends up almost identical to yours except that with mine you can turn off all the delays by commenting out one line whereas with yours you'd need to rewrite it to get rid of all the setTimeouts.

    Anyway how many JavaScript beginners know how to use setTimeout properly - very few. Being able to insert a statement for the delay would be easier for them than having to manually rewrite their code to add in the setTimeouts.

    AGAIN why go to all the trouble of rewriting your code when JavaScript can rewrite it for you so that you don't have to. Would you really weant to go to all the trouble of the rewrites if you had 1000 different functions that needed to have a delay added into them or would you prefer to let JavaScript apply most of the changes for you.

    My code uses setTimeouts alsmost identically with yours except that mine generates all the necessary changes automatically just by inserting sleep lines where you want to split the function up and one call per function to allowSleep to get JavaScript to rewrite that function for you so that you don't have to (making it extra easy for those who don't know how to rewrite it to insert the delay).

    I suppose you manually rewrite all your functions when you need to memoize them as well rather than letting JavaScript do it for you.
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • #6
    Supreme Master coder! Philip M's Avatar
    Join Date
    Jun 2002
    Location
    London, England
    Posts
    18,079
    Thanks
    203
    Thanked 2,542 Times in 2,520 Posts
    Quote Originally Posted by felgall View Post
    If you do that (omit the var keyword) then strict JavaScript will refuse to run because it requires that all variables be declared before you can use them.
    Yes, I agree, personally I would never omit the var keyword and I always declare my variables before using them. Whether required or not I consider it to be good coding practice.


    Quote Originally Posted by felgall View Post
    I suppose you manually rewrite all your functions when you need to memoize them as well rather than letting JavaScript do it for you.
    Well, yes, I do manually rewrite any code which requires it. In reality I don't find this happens very often, nor in reality do I have 1000 different functions which need to have a delay added into them. I do not write code on an industial scale - all my clients are pretty modest businesses or clubs.

    I think you sometimes spoil your case by exaggeration. How many million times have I invited you not to do that?
    Last edited by Philip M; 06-02-2012 at 09:21 AM.

    All the code given in this post has been tested and is intended to address the question asked.
    Unless stated otherwise it is not just a demonstration.

  • #7
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,642
    Thanks
    0
    Thanked 649 Times in 639 Posts
    Quote Originally Posted by Philip M View Post
    nor in reality do I have 1000 different functions which need to have a delay added into them.
    but if just 1000 people grab a copy of my code and use it to insert a delay into just two functions each then that's 2000 functions that didn't have to be rewritten because my code did it for them.

    Suggesting that my code could save one person rewriting 1000 functions might be an exaggeration but if lots of people use it then not having to rewrite 1000 functions between them could be a huge underestimate.

    Plus when you make that big a change to your code you need to do a significant amount of testing in case you made an error in the replacement code. Since my code is already tested and only requires minor changes to the original code in order to use it only minimal testing would be required.

    Also my original idea was to create a modal lightbox script that behaves similarly to alert in that it waits for a response before allowing the code to continue but where the lightbox is written in HTML and so can contain whatever content you need - with a design to match your site. Such a script would require similar modifications to the original function in order to work but with the subsequent function being called from the lightbox rather than via setTimeout. Slight modifications to the allowSleep method would allow it to perform similar changes for a lightbox to function asynchronously while simply adding a single statement into the original code at the point where the lightbox is to be called - for example to take an old script that uses alert calls and simply substitute a lightbox version of alert without rewriting the original function.

    And just as one additional reason why my script would be useful is that I have seen a lot of forum questions scattered across the web with people asking how to create a sleep function in JavaScript without getting an answer - my script answers their question on how to implement sleep() in JavaScript.
    Last edited by felgall; 06-02-2012 at 09:40 AM.
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • #8
    Supreme Master coder! Philip M's Avatar
    Join Date
    Jun 2002
    Location
    London, England
    Posts
    18,079
    Thanks
    203
    Thanked 2,542 Times in 2,520 Posts
    What do you think of my horrible snooze() function I addded to Post#4? Note that it is modal - it suspends program execution. But I have to say that it works!

    All the code given in this post has been tested and is intended to address the question asked.
    Unless stated otherwise it is not just a demonstration.

  • #9
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,642
    Thanks
    0
    Thanked 649 Times in 639 Posts
    Quote Originally Posted by Philip M View Post
    What do you think of my horrible snooze() function I addded to Post#4? Note that it is modal - it suspends program execution. But I have to say that it works!
    It works until either your visitor tries to run some other JavaScript during the snooze or the browser decides that the script is taking too long to run and asks if it should cancel the script. Try running that script with a 10 minute delay and the browser will complain about the script taking too long to run - also you would not be able to do anything else on the computer for the first minute or two until the browser gives the option to cancel the script.

    Solutions like that as well as ones calling Java, Flash or using synchronous XMLHttpRequest to call the server to make use of a sleep() function built into one of those languages avoids the 100% CPU issue but still prevent any other JavaScript from running since JavaScript is single threaded and so only one script can run at a time. At least by not using 100% CPU they allow other things to run on the computer. All the pages I could find on the subject mention one or all of these four alternatives. I couldn't find anywhere that suggested a fifth way of implementing a JavaScript sleep function - so I set out to create one.

    All of the pages that I could find on the subject all concluded that using setTimeout is the only way to implement a single delay in JavaScript without locking up the browser (some browsers released JavaScript while the Java or Flash were running but others didn't). None of the pages that I could find on the subject provided a workable solution that is implemented by placing a function call into the code.

    The code I posted here is my attempt to produce a JavaScript sleep function that can be inserted into a function in the same way a sleep call can be added to Java, Flash, PHP etc. it is the fifth way that none of the other pages show and has the advantage that subject to certain limitations it actually works without the problems of the other four ways. It converts the function into two (or more) using setTimeout to implement the sleep so that other JavaScript can run in between and the browser will not complain about a script running for too long if you specify a longer delay. The only two issues it has is that it can't be used in a loop and it doesn't prevent anything after the function ends from running. it doesn't use 100% of the CPU and it doesn't prevent other JavaScript from running during the sleep.
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • #10
    Supreme Master coder! Philip M's Avatar
    Join Date
    Jun 2002
    Location
    London, England
    Posts
    18,079
    Thanks
    203
    Thanked 2,542 Times in 2,520 Posts
    Quote Originally Posted by felgall View Post
    It works until either your visitor tries to run some other JavaScript during the snooze or the browser decides that the script is taking too long to run and asks if it should cancel the script. Try running that script with a 10 minute delay and the browser will complain about the script taking too long to run - also you would not be able to do anything else on the computer for the first minute or two until the browser gives the option to cancel the script.
    I thought that modal meant that program execution is suspended (as with an alert) and no other script could run during the snooze - that is the idea, surely.

    Script takes too long causing browser warning - IE limits JavaScript execution to 5 million statements. Firefox uses a timed limit of 10 seconds. Chrome and Opera do not seem to limit execution time.

    But in practice who will require a delay longer than 10 seconds? The user will get impatient if nothing happens (or can happen) for 10 seconds!

    However, if you want to handle longer delays the trick is to break it up into smaller sections and then use setTimeout() or setInterval() with a delay of 0 between them. Even a zero delay will return control to the browser long enough for the warning about execution time to never trip.

    I find that the script only charges the CPU to around 60% on my current computer with 4GB memory. In any case, why does it matter even if it does charge the CPU to 100%?

    I have downgraded my assessment of the script from "horrible" to "kludge"!
    Last edited by Philip M; 06-03-2012 at 09:46 AM.

    All the code given in this post has been tested and is intended to address the question asked.
    Unless stated otherwise it is not just a demonstration.

  • #11
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,642
    Thanks
    0
    Thanked 649 Times in 639 Posts
    Quote Originally Posted by Philip M View Post
    I have downgraded my assessment of the script from "horrible" to "kludge"!
    I agree with the "kludge" assessment however it is the only way to even partially implement an actual "sleep" command in JavaScript - it does at least work consistently provided you stay within its limitations - whereas the four alternatives all result in locking up one browser or another. When the choice is between a kludge and something that doesn't work then the kludge is the better alternative. Of course you can avoid the kludge by rewriting all the code yourself instead of letting the script rewrite it for you but not everyone knows how to do that.

    Of course it does matter that one of the alternatives takes the cpu to 100% since there are quite possibly going to be other things running on the computer at the same time so it blocks those from running - or at least slows them down. Also from what I have read all four of the alternatives can result in the entire system locking up and requiring a reboot (depending on which browser you are using and what else is running) - not something you want your JavaScript to be causing to happen even occassionally.

    Also as a step toward being able to create your own modal alert all four alternatives suffer from the problem of locking out other JavaScript processes from starting which would prevent the click of the alert close button being detected if you were using the code to implement a modal dialog that waits for the response.

    Your proposed fixes for several of the issues is to use setTimeout which I agree is the only way. Also the only way to insert setTimeout into an existing function without rewritiing the function into multiple functions yourself - which results in your no longer having a sleep() call in the middle of a function - is the solution that I presented in this script.

    So unless you present an alternative sleep() function that uses setTimeout that can simply be inserted into an existing function without having to manually rewrite the function yourself I believe that we are in complete agreement with regard to setTimeout being the best solution and this script being the only way to implement it without having to manually rewrite the code into separate functions.
    Last edited by felgall; 06-03-2012 at 08:36 PM.
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • Users who have thanked felgall for this post:

    Philip M (06-05-2012)

  • #12
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,373
    Thanks
    11
    Thanked 592 Times in 572 Posts
    i would say that it's an ok idea.

    i don't like passing function names as strings, and you forgot the valid underscore name char, but i encourage this type of language extension/modification.

    i have been collecting many such extensions into a beta/POC group i call magic, but it's more a collection of neat stand-alones than a comprehensive library.

    http://danml.com/magic/

    you will see that in particular, my class, strong-typing and async-written-as-sync (sentry) functions use functionBody sniffing just like your sleep() does.

    there's other stuff in there, but i thought i'd share a "here here" for dynamic code generation.

    interesting stuff, and a good post; thanks felgall.
    my site (updated 13/9/26)
    BROWSER STATS [% share] (2014/9/03) IE7:0.1, IE8:4.6, IE11:9.1, IE9:3.1, IE10:3.0, FF:17.2, CH:46, SF:11.4, NON-MOUSE:38%

  • #13
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,642
    Thanks
    0
    Thanked 649 Times in 639 Posts
    Quote Originally Posted by rnd me View Post
    i don't like passing function names as strings
    Do you know of an alternative way to get the function name from within a function method - I couldn't find one.

    Quote Originally Posted by rnd me View Post
    and you forgot the valid underscore name char
    no I didn't - \w is equivalent to [a-zA-Z0-9_] so the only character you need to add to that which is valid in function names is $


    See http://www.felgall.com/jstip115.htm where I basically set up the same thing but where it replaces the alert() calls in the function with custom alerts instead.
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • #14
    Senior Coder rnd me's Avatar
    Join Date
    Jun 2007
    Location
    Urbana
    Posts
    4,373
    Thanks
    11
    Thanked 592 Times in 572 Posts
    Quote Originally Posted by felgall View Post
    Do you know of an alternative way to get the function name from within a function method - I couldn't find one.
    function.name||function.Name() - using a fall-back prototype like this one:
    Code:
    Function.prototype.Name=function(){return String(this).split("(")[0].split(" ")[1]};
    Quote Originally Posted by felgall View Post
    no I didn't - \w is equivalent to [a-zA-Z0-9_] so the only character you need to add to that which is valid in function names is $
    doh! you're right. for some reason, i always forget that and use[\w$_]. silly me.


    that said, you don't need the function names at all.

    here is a slightly different take, with another set of strengths and weaknesses.

    you don't have to setup this version, it works just by calling. this makes it a bit simpler than the one posted. one thing about it is that you have to return the sleep each call. this seems weird i know, but it help prevent mis-sniffs, and self-documents that the "flow ends here". the only way around it i could find was using a throw, but that's ugly.

    it doesn't close vars, so keep that in mind. this let me avoid eval(), but it does sacrifice some function capability.
    if you want to close vars, you will need to blow eval inside the sleepy function. no way around it. i didn't want to, so this keeps it as clean as possible.



    tested in ff, chrome, and ie:

    Code:
    function sleep(n){
     var delay=0, pcode=arguments.callee.caller;
      if( sleep[pcode] ){ return; }else{ sleep[pcode]=1; }
      var toRun=pcode.toString().slice(0,-1).split(/return\s+sleep\s*\((\s*\d+\s*)\)/g).slice(1);
      for(var a, i=0, mx=toRun.length; i<mx; i++){
         a=toRun[i]
         if(+a){ delay+=+a }else{ setTimeout( Function(a), delay ) }
      }//next
    }//end sleep()
    
    
    //a generic example function to test sleep() operation:
    function afunc() {
      document.title = 'first message';
      return sleep(5000); 
    
      document.title = 'message the second';
      return sleep(3000);
    
      document.title = 'message the third';
      return sleep(3000);
    
      document.title = 'last message';
    }
    
    afunc()
    Last edited by rnd me; 06-24-2012 at 01:58 PM.
    my site (updated 13/9/26)
    BROWSER STATS [% share] (2014/9/03) IE7:0.1, IE8:4.6, IE11:9.1, IE9:3.1, IE10:3.0, FF:17.2, CH:46, SF:11.4, NON-MOUSE:38%

  • #15
    Senior Coder
    Join Date
    Sep 2010
    Posts
    2,029
    Thanks
    15
    Thanked 240 Times in 240 Posts
    Actually there is a way to implement a blocking type 'sleep' in javascript, it's rather crude and rude from the user standpoint, but it will do the job if needed. Just put up an alert which says 'Please click OK after three seconds.


  •  
    Page 1 of 2 12 LastLast

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •