DEV Community

Chinmay
Chinmay

Posted on

setTimeout - max timeout footgun

Recently I discovered a footgun in real life, which was related to setTimeout, I had to run a timeout for say 28 days for a sale timer, I had a UTC timestamp for the end day, so with the naive approach, I did this

 const date1 = new Date(timestamp1);

  // Difference in milliseconds
  const timeout = date2.getTime() - Date.now();

setTimeout(()=>{
     // some code to turn off some flags / remove some banner
  },timeout);
Enter fullscreen mode Exit fullscreen mode

To my surprise, this did not work or worked too well, since the code within setTimeout executed without waiting for the timeout, I decided to debug in the browser, and I saw that the control jumps into the setTimeout callback almost instantly.

What's the problem here ?

Looking at MDN page of setTimeout, https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value , it was clear that there is a max limit until which setTimeout() will run accurately, specifically
2,147,483,647ms or (24.8 days) or (2**31 - 1) ms, this is because browsers store the delay as a 32-bit signed integer internally.

So whenever you pass in a timeout of more than 24.8 days, there is an integer overflow and the code is executed immediately or rather with a lower timeout duration than expected. That's a bummer, and there is no error !!!

Possible solutions for this problem


const days = 30;
const timeout = days * 24 * 60 * 60 * 1000;
console.log('timeto', timeout);
setTimeout(function () {
  console.log('ticked immediately'); // --> executed almost instantly 
}, timeout);


class LongTimeout {
  constructor(cb, timeout) {
    this.timeStart = document.timeline
      ? document.timeline.currentTime
      : performance.now();
    this.lastAnimationFrame = this.runTimer(cb, timeout);
  }
  runTimer(cb, timeout) {
   if(this.cancelled) return;
    const currTimeStamp = performance.now();
    const elapsed = currTimeStamp - this.timeStart;
    if (elapsed >= timeout) {
      cb();
      window.cancelAnimationFrame(this.lastAnimationFrame);
    } else {
      console.log('tick', elapsed, timeout);
      this.lastAnimationFrame = requestAnimationFrame(() =>
        this.runTimer(cb, timeout)
      );
    }
  }
  cancelTimeout() {
    window.cancelAnimationFrame(this.lastAnimationFrame);
    this.cancelled = true;
    this.lastAnimationFrame = null;
  }
}

const longTimer = new LongTimeout(() => {
  console.log(`Tick after ${timeout}`); // timeout works -> does not execute immediately
}, timeout);

Enter fullscreen mode Exit fullscreen mode

Image of Datadog

The Future of AI, LLMs, and Observability on Google Cloud

Datadog sat down with Google’s Director of AI to discuss the current and future states of AI, ML, and LLMs on Google Cloud. Discover 7 key insights for technical leaders, covering everything from upskilling teams to observability best practices

Learn More

Top comments (0)