requestAnimationFrame vs. setTimeout: Why Frame Sync Matters More Than You Think
A timer-driven animation on a background tab keeps burning CPU cycles for no visible output; rAF stops that automatically. Getting the execution slot right also avoids an entire class of layout thrashing bugs that are easy to create and hard to diagnose.
Timers like setTimeout and setInterval run as macro-tasks in the event loop with no connection to the rendering cycle, so a callback can fire mid-frame, miss a frame entirely, or stack up multiple times per frame. requestAnimationFrame instead hooks into the render pipeline, executing its callback queue after JS tasks finish but before style calculation and layout begin. That placement guarantees style changes are processed in the current frame.
The API also auto-pauses when a tab is hidden, passes a microsecond-precision DOMHighResTimeStamp for progress calculation, and returns a handle that cancelAnimationFrame can abort. The standard pattern uses elapsed time rather than fixed pixel increments, keeping total duration consistent even when frame rate dips.
Common traps include assuming rAF fires on a fixed 16.6ms interval (it tracks the display's actual refresh rate and yields when the main thread is blocked) and believing rAF alone makes animation smooth. If per-frame work exceeds the budget, jank still happens. The API is also useful beyond animation for chunked DOM updates and avoiding forced synchronous layouts.
The mental model shift is subtle but consequential: rAF is not a timer replacement but a render-pipeline hook. Developers who treat it as a faster setTimeout miss the scheduling guarantee that makes it valuable.
The 4ms minimum delay on setTimeout is often cited as a precision problem, but the real damage is the unpredictable slot within the event loop. Even a 0ms timeout can land after the current frame's paint, creating a full frame of latency.
High-refresh-rate displays (120Hz, 144Hz) shrink the per-frame budget to 8.3ms or less. On those devices, the difference between a correctly scheduled rAF callback and a timer callback that misses the frame boundary becomes visibly sharper.