8

In javascript, setTimeout is forced to be >= 4 msec

 3 years ago
source link: https://blog.klipse.tech/javascript/2016/10/31/setTimeout-0msec.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

In javascript, setTimeout is forced to be >= 4 msec

Oct 31, 2016 • Yehonathan Sharvit

Javascript is a language full of surprises: there are the good parts and the bad parts. Today, I discovered that setTimeout featured a minimal delay of 4 msec.

This is well documented in Reasons for delays longer than specified.

But I wonder, how many experienced javascript developers are aware of this weird behaviour.

What about you?

Did you know that the minimal delay of setTimeout was 4 msec?

In this article, we are going to:

  1. demonstrate the 4 sec delay added by the browser when one uses a setTimeout with 0 delay.
  2. demonstrate how to write 0-delay timers using postMessage.
Stop

Code example

All the code snippets of this page are live and interactive powered by the klipse plugin:

  1. Live: The code is executed in your browser
  2. Interactive: You can modify the code and it is evaluated after 3 seconds of inactivity of if you press Ctrl-Enter inside the code snippet.

The 4 msec delay in action

Here is the code that demonstrates the 4-msec delay - calling setTimeout recursively 100 times with a 0 delay.

As you can see by yourslef, the execution time for 100 iterations is around 400 msec.

You might need to reevaluate the snippet - for some reason the first evaluation takes much more time.

Press Ctrl-Enter inside the code snippet or modify the code and wait for 3 seconds…

xxxxxxxxxx
function bar(iterations) {
  if(iterations === 0) {
    console.log("done in: " + (new Date() - startTimeout)+ " msec")
  }
  else {
    setTimeout(bar, 0, iterations - 1);
  }
}
startTimeout = new Date();
console.log("Start");
bar(100);
"Start"

Amazing. No?

The solution for fast timeouts

If we want to have a 0 msec timer, we have to use postMessage.

So, let’s do it and take the following code from setTimeout with a shorter delay.

setZeroTimeout takes a single argument: the callback function that is going to be called with 0 delay - but asynchronously.

xxxxxxxxxx
(function() {
  var timeouts = [];
  var messageName = "zero-timeout-message";
  function setZeroTimeout(fn) {
    timeouts.push(fn);
    window.postMessage(messageName, "*");
  }
  function handleMessage(event) {
    if (event.source == window && event.data == messageName) {
      event.stopPropagation();
      if (timeouts.length > 0) {
        var fn = timeouts.shift();
        fn();
      }
    }
  }
  window.addEventListener("message", handleMessage, true);
  window.setZeroTimeout = setZeroTimeout;
})();
xxxxxxxxxx
undefined

And now, let’s see it in action - in my browser, it takes around 17 msec for 100 iterations.

Again, you might need to reevaluate the snippet - as the first evaluation takes much more time.

Press Ctrl-Enter inside the code snippet or modify the code and wait for 3 seconds…

xxxxxxxxxx
function runBaz(iterations) {
  function baz() {
    if(--iterations === 0) {
      console.log("done in: " + (new Date() - startZeroTimeout) + " msec")
    }
    else {
      setZeroTimeout(baz);
    }
  }
  baz();
}
startZeroTimeout = new Date();
console.log("OK");
runBaz(100);
xxxxxxxxxx
"OK"
"done in: 276 msec"

By the way, what do you think about the interactive code snippets powered by KLIPSE?

You might what to give a star on Github


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK