91

I need to add a delay of about 100 miliseconds to my Javascript code but I don't want to use the setTimeout function of the window object and I don't want to use a busy loop. Does anyone have any suggestions?

Michael Gaskill
  • 7,913
  • 10
  • 38
  • 43
JGC
  • 12,737
  • 9
  • 35
  • 57
  • 18
    Can you explain why setTimeout isn't appropriate/doesn't meet your needs? – eyelidlessness Jul 26 '09 at 06:24
  • @eyelidessness sometimes inserting a setTimeout(...) it might involve having to update a whole load of unit tests, using jest fake timers etc. – AndyUK Feb 13 '20 at 10:19

6 Answers6

152

Unfortunately, setTimeout() is the only reliable way (not the only way, but the only reliable way) to pause the execution of the script without blocking the UI.

It's not that hard to use actually, instead of writing this:

var x = 1;

// Place mysterious code that blocks the thread for 100 ms.

x = x * 3 + 2;
var y = x / 2;

you use setTimeout() to rewrite it this way:

var x = 1;
var y = null; // To keep under proper scope

setTimeout(function() {
    x = x * 3 + 2;
    y = x / 2;
}, 100);

I understand that using setTimeout() involves more thought than a desirable sleep() function, but unfortunately the later doesn't exist. Many workarounds are there to try to implement such functions. Some using busy loops:

function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}

others using an XMLHttpRequest tied with a server script that sleeps for a amount of time before returning a result.

Unfortunately, those are workarounds and are likely to cause other problems (such as freezing browsers). It is recommended to simply stick with the recommended way, which is setTimeout()).

Andrew Moore
  • 93,497
  • 30
  • 163
  • 175
  • 3
    **@James M.:** Totally Agree... I never understood why there is such a big stigma around `setTimeout()`. – Andrew Moore Jul 26 '09 at 07:05
  • 4
    I don't believe setTimeout() has any stigma surrounding it, its just that it doesn't always produce the desired effect easily. Say, for instance, if you want to idle the processor for a short period of time while in a process intensive loop to avoid locking up the browser. Achieving this result with setTimeout can be difficult for inexperienced JavaScript programmers. – KingRadical Dec 29 '09 at 20:39
  • 1
    That script works for me up to around 9 seconds. After that it stays around 9 seconds. Maybe it's that `1e7` value? – Nathan H Oct 19 '15 at 08:00
  • "but unfortunately the later doesn't exist." Did you mean to say "latter"? – FluorescentGreen5 May 06 '17 at 12:37
  • Im new to js. How would I call the above delay script? I have a loop im trying to delay using this function. I tried function sleep (2000){...}. But that's not working. – user982853 May 22 '19 at 14:58
  • @user982853 Simply `sleep(2000)`. But, don't use it, because of the reasons explained in the answer – FZs Aug 25 '19 at 17:00
  • For anybody using node.js it is worth noting this would be asynchronous, so your code will first continue executing past the setTimeout call and then do the actual statements within it later. – nsandersen Oct 02 '19 at 12:10
  • This is the ideal method for "putting a delay in javascript". It might not be "browser friendly" but when you are debugging code, sometimes you need to break the browser and thus, the reason for a sleep function. I cant think of any other use for sleep function except making the code really really slow so the customer thinks it looks "even faster" when they come to see the progress. :) – Stephen Duffy Apr 28 '22 at 09:29
30

If you're okay with ES2017, await is good:

const DEF_DELAY = 1000;

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms || DEF_DELAY));
}

await sleep(100);

Note that the await part needs to be in an async function:

//IIAFE (immediately invoked async function expression)
(async()=>{
  //Do some stuff
  await sleep(100);
  //Do some more stuff
})()
FZs
  • 16,581
  • 13
  • 41
  • 50
Nicholas Blasgen
  • 772
  • 7
  • 13
16

I just had an issue where I needed to solve this properly.

Via Ajax, a script gets X (0-10) messages. What I wanted to do: Add one message to the DOM every 10 Seconds.

the code I ended up with:

$.each(messages, function(idx, el){
  window.setTimeout(function(){
    doSomething(el);
  },Math.floor(idx+1)*10000);
});

Basically, think of the timeouts as a "timeline" of your script.

This is what we WANT to code:

DoSomething();
WaitAndDoNothing(5000);
DoSomethingOther();
WaitAndDoNothing(5000);
DoEvenMore();

This is HOW WE NEED TO TELL IT TO THE JAVASCRIPT:

At Runtime 0    : DoSomething();
At Runtime 5000 : DoSomethingOther();
At Runtime 10000: DoEvenMore();

Hope this helps.

user2390733
  • 501
  • 1
  • 5
  • 7
  • Thanks for the answer explaining SetTimeOut behavior. The issue is that later on when the code is long, or depends on server responses, it becomes difficult to even visualize the actual timeline in seconds. – Gaurav Ojha Jan 02 '17 at 07:36
4

Actually only setTimeout is fine for that job and normally you cannot set exact delays with non determined methods as busy loops.

sth
  • 222,467
  • 53
  • 283
  • 367
stoimen
  • 562
  • 3
  • 7
3

This thread has a good discussion and a useful solution:

function pause( iMilliseconds )
{
    var sDialogScript = 'window.setTimeout( function () { window.close(); }, ' + iMilliseconds + ');';
    window.showModalDialog('javascript:document.writeln ("<script>' + sDialogScript + '<' + '/script>")');
}

Unfortunately it appears that this doesn't work in some versions of IE, but the thread has many other worthy proposals if that proves to be a problem for you.

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • 3
    Seems like a solution waiting for a problem. I can't think of a single situation in which `setTimeout` would not do its job. But +1 for creativity. :) – Sasha Chedygov Jul 26 '09 at 06:41
-13

Use a AJAX function which will call a php page synchronously and then in that page you can put the php usleep() function which will act as a delay.

function delay(t){

var xmlhttp;

if (window.XMLHttpRequest)

{// code for IE7+, Firefox, Chrome, Opera, Safari

xmlhttp=new XMLHttpRequest();

}

else

{// code for IE6, IE5

xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");

}

xmlhttp.open("POST","http://www.hklabs.org/files/delay.php?time="+t,false);

//This will call the page named delay.php and the response will be sent to a division with ID as "response"

xmlhttp.send();

document.getElementById("response").innerHTML=xmlhttp.responseText;

}

http://www.hklabs.org/articles/put-delay-in-javascript

Jubin Patel
  • 1,959
  • 19
  • 38
Kaushik
  • 1
  • 2
  • 20
    Don't forget the basics of web design. The fundamental principle is to reduce server load as much as you can. For a simple time delay you are requesting a page from the server infinite number of times. Just think about what you are doing here. – Arun Aravind Oct 06 '13 at 09:11
  • 1
    You've killed him – Alex Hawking Jun 10 '20 at 05:29