Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do timeout and interval in JavaScript use monotonic time?

Suppose I call setTimeout(() => {...}, 1000), i.e, a 1 second wait, but the computer has its internal clock wrong. After 500ms, the OS receive a NTP update, realize its clock was 30 second in the future, and thus set back its clock 30 second. When will my timeout fire? In 500ms, monotonic time; or 30500ms, wall clock time?

If its in 30 second... is there a way to set up a timer that will fire correctly after 500ms as measured with performance.now()?

Do the behavior vary between browser?


Note: of course you'll never get a highly accurate setTimeout, because browser mitigate Spectre and old code rely on a minimum delay, but my question is about the huge jump in time du to a change in the internal clock.

like image 237
Laurent Bourgault-Roy Avatar asked Sep 29 '26 04:09

Laurent Bourgault-Roy


1 Answers

By running the following snippet in different browsers and looking at the behavior when changing the OS clock time in different OSes.

The different tests: Test 1:

  • Run the snippet
  • Set time in the future (within 30 secs)
  • Check results

Test 2:

  • Run the snippet
  • Set time in the past (within 30 secs)
  • Check results

Test 3:

  • Run the snippet
  • Set time in the past (within 30 secs)
  • Set time in the future (within 30 secs)
  • Check results

Test 4:

  • Run the snippet
  • Set time in the future (within 30 secs)
  • Set time in the past (within 30 secs)
  • Check results

Every test that I have ran was repeated 5 times.

const perfor = () => {
  console.log(performance.now());

  window.requestAnimationFrame(perfor);
}

window.requestAnimationFrame(perfor);

setTimeout(() => {
  alert('HI');
}, 30000);

Testing on Windows 10(OS Build 19041.508) with all browsers being a 64-bit build: Test 1:

                              | setTimeout           | perfor     |
------------------------------|----------------------|------------|
Firefox 81.0.2                | fired after ~30 secs | kept going |
Firefox 82.0.1                | fired after ~30 secs | kept going |
Google Chrome 86.0.4240.111   | fired after ~30 secs | kept going |
Microsoft Edge 44.19041.423.0 | fired after ~30 secs | kept going |

Test 2:

                              | setTimeout           | perfor                      |
------------------------------|----------------------|-----------------------------|
Firefox 81.0.2                | fired after ~30 secs | stopped when time rewinded* |
Firefox 82.0.1                | fired after ~30 secs | kept going                  |
Google Chrome 86.0.4240.111   | fired after ~30 secs | kept going                  |
Microsoft Edge 44.19041.423.0 | fired after ~30 secs | kept going                  |

Test 3:

                              | setTimeout           | perfor                      |
------------------------------|----------------------|-----------------------------|
Firefox 81.0.2                | fired after ~30 secs | stopped when time rewinded* |
Firefox 82.0.1                | fired after ~30 secs | kept going                  |
Google Chrome 86.0.4240.111   | fired after ~30 secs | kept going                  |
Microsoft Edge 44.19041.423.0 | fired after ~30 secs | kept going                  |

Test 4:

                              | setTimeout           | perfor                      |
------------------------------|----------------------|-----------------------------|
Firefox 81.0.2                | fired after ~30 secs | stopped when time rewinded* |
Firefox 82.0.1                | fired after ~30 secs | kept going                  |
Google Chrome 86.0.4240.111   | fired after ~30 secs | kept going                  |
Microsoft Edge 44.19041.423.0 | fired after ~30 secs | kept going                  |

* In Firefox 81.0.2 the logging of performance.now() stopped when I set the OS time in relativity to the past. So if I set my year, month or day in the future and then set set my year, month or day for me in the future but for the machine now in the past Firefox 81.0.2 will stop with logging the performance.now(). I could not find a reason for why and how this happens and why it is fixed in 82.0.1.

NOTE: I could test Firefox in multiple versions because I had an update.

I invite other users to run these and edit to add there results

performance.now() will show the milliseconds since the tab is opened. This is not effected in Windows 10 by changing the OS clock time.

like image 198
TessavWalstijn Avatar answered Sep 30 '26 17:09

TessavWalstijn