A working 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.

This 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.

<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+"();};\
sleep("+t+","+n+".f"+i+");\
"+(i==1?"":"}\
")+n+".func" + i +" = function() {";});
  eval(n+'='+f+'\
}');
}
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.

Does anyone have any suggestions on how to extend this so it works for those cases as well?

Not on how to extend it, but I’ve slightly refactored the function so that it’s easier to understand what is going on in there.


Function.prototype.allowSleep = function (funcName) {
    if (!/^[$\\w]+$/.test(funcName)) {
        return;
    }
    var i = 0,
        sleepFuncRx = /sleep\\((.*?)\\);/g,
        sleepInjector = function (dummy, time) {
            i += 1;
            var sleepFunc = funcName + '.f' + i,
                afterSleepFunc = funcName + '.func' + i,
                before = sleepFunc + ' = function() {' + afterSleepFunc + '();' + '};\
',
                during = 'sleep(' + time + ',' + sleepFunc + ');\
',
                nestedBrace = (i === 1 ? '' : '}\
'),
                after = nestedBrace + afterSleepFunc + ' = function() {';
            return before + during + after;
        },
        sleepingFunc = this.toString().replace(sleepFuncRx, sleepInjector);
    eval(funcName + '=' + sleepingFunc + '\
}');
};

Another approach could use a global variable. On first call of the setTimeout it can check the variable to see if its a first call or not.
On first call it can set the global variable to mark something as not first e.g. >0 value and no processing to be done with this.
On succeeding calls simply clear time out.

Just a thought.

No - global variables are bad. Most especially globals should not be used when a local variable will do instead.
Global Variables in JavaScript
Global variables (from JSLint)
Awful Parts of JavaScript

These other places are about how to improve your usage of JavaScript, in ways that make your life easier and better.
Avoid cluttering the global namespace
From slide #17 of the JavaScript Best Practices presentation

Paul, thanks for your response. As you do not have any suggestions for a way to bypass the limitations I mentioned I am closer to being convinced that this is as close as JavaScript can get to a sleep function that can be coded the same way as in other languages.

I agree. Because JavaScript doesn’t control it’s execution context, techniques from other languages just aren’t viable in that sort of regard. JavaScript just cannot afford to use the blocking context that would be required in which to achieve such a sleep function. The best way for javascript still seems to be to package up what is intended to be executed later on, and to use some kind of mediator pattern in which to manage the timings and execution of things.

That’s basically what my sleep() function does for the situations where the original script allows for it to be rewritten to do that using JavaScript itself to do the rewriting.

Here’s a similar script that produces a custom alert - subject to the same restrictions and using sm() and hm() as the show and hide functions for displaying the modal dialog (calling those functions in the modal dialog script I wrote six years ago at http://javascript.about.com/library/blmodald1.htm to save me having to rewrite that part while getting the rest to work).

alert = function(t,f) {
var d, d2, e, n;
if (f === undefined) return;
d = document.createElement('div');
d.id = 'alertbox';
d.className ='dialog';
d2 = document.createElement('div');
d2.style.textAlign = 'center';
e = document.createElement('span');
n = document.createTextNode(t);
e.appendChild(n);
d2.appendChild(e);
d2.appendChild(document.createElement('br'));
e = document.createElement('button');
n = document.createTextNode('OK');
e.appendChild(n);
e.id = 'alertbutton';
d2.appendChild(e);
d.appendChild(d2);
document.getElementsByTagName('body')[0].appendChild(d);
sm('alertbox',200,50);
document.getElementById('alertbutton').onclick = f;
}
clearAlert = function() {
var a = document.getElementById('alertbox');
hm('alertbox');
a.parentNode.removeChild(a);
}

Function.prototype.allowAlert = function(n) {
   var i, f;
  i = 0;
  f = this.toString().replace(/alert\\((.*?)\\);/g , function(x,t) {i++; return n+".f"+i+" = function() {clearAlert();\
"+n+".fa"+i+"();};\
alert("+t+","+n+".f"+i+");\
"+(i==1?"":"}\
")+n+".fa" + i +" = function() {";});
  eval(n+'='+f+'\
}');
}

 
afunc = function() {
  document.getElementById('text').innerHTML = 'first message';
  alert('one');
  document.getElementById('text').innerHTML = 'message the second';
  alert('two');
  document.getElementById('text').innerHTML = 'last message';
   }
afunc.allowAlert('afunc');
afunc();

I still haven’t got around to refactoring the code just yet - I usually leave that until after I am happy that it works as intended, plus these are still just experiments to see how closely I can reproduce the JavaScript alert() functionality while providing the ability to style it however you want in the web page (the sleep version was one step along the way). My modal dialog script is overdue for a rewrite so when I do that I’ll incorporate a refactored version of this experiment into it.

At least then beginners trying to emulate sleep() or wanting their own custom dialogs will be able to see a way to do it that at least works provided that all the code is inside the one function and they don’t need to make any calls inside of loops.

[URL=“http://www.sitepoint.com/forums/”]

Hi fellgal, I tried to send you a pm, but its seems you dont accept them, or it just wouldnt send to you. I am looking for a programmer to develop a web application and wanted to see if your interested and go over the details with you. Please send me a pm of how we could discuss this.

Thanks