Facebook Pixel

Trust Issues With setTimeout in JavaScript

setTimeout does not guarantee exact timing. Here is why you cannot trust it and what to do instead.

Trust Issues With setTimeout in JavaScript

setTimeout does not guarantee that the callback will run exactly after the specified delay. It guarantees a minimum delay, not an exact one. This is why there are "trust issues" with setTimeout.

The Promise

setTimeout(() => console.log("hi"), 1000);

You might expect "hi" to log exactly 1000ms later. It will not.

The Reality

The callback runs at least 1000ms later. The actual delay depends on:

  1. The call stack: if synchronous code is still running, the callback waits in the queue.
  2. The microtask queue: the event loop drains all microtasks before any macrotask.
  3. Timer throttling: browsers throttle timers in background tabs (often to 1000ms).
  4. Nested timers: after 5 nested levels, browsers may enforce a 4ms minimum.
  5. Clamping: some browsers clamp very small delays to a minimum.

Example: Blocking the Stack

setTimeout(() => console.log("timer"), 1000); function block() { const start = Date.now(); while (Date.now() - start < 5000) {} } block(); // "timer" logs after 5 seconds, not 1 second

The timer fired at 1 second, but the callback was queued. The event loop could not run it until block returned.

What to Do Instead

  1. For animations: use requestAnimationFrame.
  2. For exact timing: use performance.now() to measure elapsed time.
  3. For scheduling: use scheduler.postTask or queueMicrotask.
  4. For idle work: use requestIdleCallback.
  5. For precise intervals: use a self-correcting timer.

Self-Correcting Timer

function preciseInterval(fn, interval) { let expected = Date.now() + interval; function step() { const drift = Date.now() - expected; if (drift <= interval) fn(); expected += interval; setTimeout(step, Math.max(0, interval - drift)); } setTimeout(step, interval); }

The Takeaway

setTimeout does not guarantee exact timing. The callback runs at least after the delay, but the actual delay depends on the call stack, microtasks, background tab throttling, and nested timer clamping. Use requestAnimationFrame for animations and a self-correcting timer for precise intervals.

No. setTimeout guarantees a minimum delay, not an exact delay. The actual delay depends on the call stack, microtask queue, background tab throttling, and nested timer clamping. The callback runs at least after the delay, but often later.

Because the callback goes to the macrotask queue. The event loop runs it only when the call stack is empty and all microtasks are done. If synchronous code or microtasks are running, the timer waits.

Yes. To save battery, browsers throttle timers in background tabs. A setTimeout(cb, 100) in a background tab might run after 1000ms or later. Do not rely on timers for background tabs.

requestAnimationFrame. It syncs with the browser's refresh rate (usually 60fps) and runs the callback before the next paint. It is smoother and more efficient than setTimeout for visual updates.

Use a self-correcting timer. Measure the drift with Date.now() or performance.now(), and adjust the next delay to compensate. This keeps the interval close to the target despite setTimeout's minimum-delay behavior.

Ready to master React completely?

Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.

Please Login.
Please Login.
Please Login.
Please Login.