html icon indicating copy to clipboard operation
html copied to clipboard

setTimeout() nesting levels: browsers do not match specification

Open majaha opened this issue 1 year ago • 1 comments

What is the issue with the HTML Standard?

None of Chrome, Firefox or Safari match the timer initialization steps. In particular, the amount of nesting that is required before the timeout is clamped to 4ms differs.

The issue is demonstrated with this code:

<!DOCTYPE html>
<html>

<head>
</head>

<body>
  <button id="run">Run</button>
  <script>
    let last = 0;
    let id = 0;
    let count = 10;

    function timeout() {
      let now = performance.now();
      console.log(now-last);
      last = now;
      id = setTimeout(timeout, 0);
      if (!count--) {
        clearInterval(id);
      }
    }

    function run() {
      console.log("START");
      count = 10;
      last = performance.now();
      clearInterval(id);
      id = setTimeout(timeout, 0);
    }


    document.querySelector("#run").addEventListener("click", run);

  </script>
</body>

</html>

By a close reading of the spec, you can trace the execution like this:

time: 0
run() 
  log("START")
  setTimeout(timeout) (nesting level: 0, timeout: 0)
time: 0
timeout()
  log(0)
  setTimeout(timeout) (nesting level: 1 timeout: 0)
time: 0
timeout()
  log(0)
  setTimeout(timeout) (nesting level: 2 timeout: 0)
time: 0
timeout()
  log(0)
  setTimeout(timeout) (nesting level: 3 timeout: 0)
time: 0
timeout()
  log(0)
  setTimeout(timeout) (nesting level: 4 timeout: 0)
time: 0
timeout()
  log(0)
  setTimeout(timeout) (nesting level: 5 timeout: 0)
time: 0
timeout()
  log(0)
  setTimeout(timeout) (nesting level: 6 timeout: 4)
time: 4
timeout()
  log(4)
  setTimeout(timeout) (nesting level: 7 timeout: 4)
...
...

Which means that by the spec, the output should be approximately:

START
0
0
0
0
0
0
4
...
...

with six 0's before the first 4.

However, both Firefox and Chrome print only four 0's before the first 4. And I think Safari prints five 0's.

So step 5 of the spec doesn't match what implementations are actually doing.

majaha avatar Jun 02 '24 06:06 majaha

cc @domenic

annevk avatar Jun 10 '24 10:06 annevk

I found this in the Chrome code, it looks like I'm not the only one who's spotted this: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/modules/scheduler/dom_timer.cc;l=272;drc=b0b102b6582fe1fca4a5eb6b156f198113674ec7;bpv=1;bpt=1?q=dom_timer.cc&ss=chromium%2Fchromium%2Fsrc

https://issues.chromium.org/issues/40141482

majaha avatar Jul 02 '24 16:07 majaha