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?
-
18Can you explain why setTimeout isn't appropriate/doesn't meet your needs?eyelidlessness– eyelidlessness2009-07-26 06:24:28 +00:00Commented Jul 26, 2009 at 6:24
-
@eyelidessness sometimes inserting a setTimeout(...) it might involve having to update a whole load of unit tests, using jest fake timers etc.AndyUK– AndyUK2020-02-13 10:19:52 +00:00Commented Feb 13, 2020 at 10:19
7 Answers
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;
}
}
}
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()).
9 Comments
setTimeout().1e7 value?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
})()
1 Comment
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.
1 Comment
Actually only setTimeout is fine for that job and normally you cannot set exact delays with non determined methods as busy loops.
2 Comments
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.
1 Comment
setTimeout would not do its job. But +1 for creativity. :)Solution for Google Apps Script users:
I couldn't get the setTimeout() function to work with Google Apps Script (just keep getting the error that the function is not defined) so I had to do something like this using the getTime() function and creating a reference time object and then an infinite loop that creates a separate time object every time it loops and checks if the value is greater than the reference time + the delay we need. I guess this way of doing it is not that precise down to the millisecond because there is looping and computational power/lag involved but for an approximate delay for something that is not a big deal weather 1 second is actually 1.013 or similar it will work.
const delay = 3000 // in ms
const date = new Date();
let time = date.getTime() + delay;
console.log('Start before delay.')
// Any code before the delay here
while(1){
const date2 = new Date(); // diffetent date object for comparison
let breaker = date2.getTime();
if (breaker>time){
console.log('Delayed message.')
break;
}
}
// Code after the delay here
1 Comment
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;
}