I'm using setTimeout to run a 30-minute countdown, but it consistently finishes around 30 seconds later than expected. I compared it with a timer on my phone and confirmed that the JavaScript version takes closer to 30 minutes and 30 seconds. What causes this delay, and what's the most reliable way to keep the countdown accurate?
3 Answers
setTimeout only guarantees a minimum delay. The callback runs when the delay has passed and the event loop is available, so browser activity, other JavaScript, background throttling, or a sleeping device can make it run later. It isn’t designed to be a precision timer.
If the countdown uses lots of repeated timeouts and simply subtracts one tick each time, even small delays can accumulate into a noticeable drift. Store the intended end time once, then calculate the remaining time from Date.now() on every update. That way, late callbacks correct themselves instead of adding more error.
Calculating the difference from a fixed end time is much more reliable than counting how many callbacks have fired.
If the page is in a background tab or the computer goes idle, browsers may throttle timers or pause work temporarily. For a countdown, use setTimeout or setInterval only to refresh the display, and use the system clock to determine whether the countdown has actually ended.

That makes sense. I was treating each timeout as if it were exact, even though the browser can postpone the callback.