3

There's a classical problem with setInterval() in browsers - if some JS code or other browser process takes too long to complete, several callback invocations might get "backed up" and you suddenly end with your callback executed multiple times in quick succession.

Often this is not what is desired when setInterval() is used. It's a typical use case when you want AT LEAST some interval of time to pass between invocations. The workaround to this is to use setTimeout() instead and only schedule the next invocation when the previous is completed.

This works well but also is extra code and might be confusing for someone who does not understand the issue.

I know that NodeJS works differently than browsers, but I cannot find any information on this particular aspect. Does NodeJS also exhibit the same behavior, or does it guarantee a minimum time between invocations when using setInterval()?

Vilx-
  • 104,512
  • 87
  • 279
  • 422
  • 1
    That's not how neither browsers nor the HTML specs do implement `setInterval` no. `setInterval(cb, dur)` is equivalent to `setTimeout(function fn() { setTimeout(fn, dur); cb(); }, dur);`(i.e a recursive setTimeout loop. Chrome goes a bit beyond and fixes the potential drift that could occur but you won't ever have "your callback executed **multiple times** in quick succession". – Kaiido Jan 18 '22 at 01:59
  • @Kaiido - It might be that browsers don't do that anymore (which would make sense), but in the past they definitely did. Here's a link to an answer that describes this behavior in detail, and there are many, many, other sources on the web that say the same: https://stackoverflow.com/a/731625/41360 – Vilx- Jan 18 '22 at 08:56
  • Yes, the whole world has completely changed in 13 years. – Kaiido Jan 18 '22 at 09:05
  • @Kaiido - That's nice. I was stuck still using the `setTimeout()` trick all the time. – Vilx- Jan 18 '22 at 12:59

1 Answers1

4

Looks like it.

start = () => {
  console.log(Date.now(), 'interval started');
  setInterval(() => console.log(Date.now(), '-'), 1000);
}
busy = (n) => {
  console.log(Date.now(), 'busy started');
  for (let i = 1; i < n; i++) Math.sqrt(i, 7);
  console.log(Date.now(), 'busy done');
}

start();
busy(1e10); // this takes a while; nothing is printed, because this keeps the node.js thread busy

Output:

1642469880773 interval started
1642469880776 busy started
1642469888272 busy done
1642469888272 -
1642469889273 -
1642469890274 -

Note the long gap between busy start and done, and how no backlog of interval callbacks seem to follow.

Christian Fritz
  • 20,641
  • 3
  • 42
  • 71