requestAnimationFrame syncs JavaScript to the browser's refresh rate (~60Hz) for smooth animations. requestIdleCallback runs low-priority work during idle periods between frames. This article explains where each fits in the frame lifecycle.
Prerequisites: Async #1 — The Event Loop
1. The Frame Lifecycle — Where rAF and rIC Fit
Every ~16ms (at 60fps), the browser tries to produce a frame:
[Macrotask] → [Microtasks] → [rAF callbacks] → [Style] → [Layout] → [Paint] → [Composite]
↑
[rIC callback]
(idle time after paint)
Loading editor...
2. requestAnimationFrame — Smooth Animations
rAF fires before the next paint, giving you ~16ms to update the DOM:
Loading editor...
3. Canceling rAF
requestAnimationFrame returns an ID — cancel with cancelAnimationFrame:
Loading editor...
4. requestIdleCallback — Do Work When the Browser is Free
rIC runs callbacks during idle periods — when the browser has nothing else to do:
Loading editor...
5. rIC with Timeout — Ensure Work Runs
Pass { timeout } to guarantee the callback fires even if the browser is never idle:
Loading editor...
6. When to Use Each
Loading editor...
Key Takeaways
- rAF fires before the next paint — use for visual updates that must be frame-perfect.
- rAF is automatically throttled when the tab is hidden — saves CPU/battery.
- rIC fires after the paint, in leftover frame time — use for analytics, cleanup, prefetching.
- rIC's
deadline.timeRemaining()tells you how much idle time is left — process in chunks. - Pass
{ timeout }to rIC for work that must eventually complete. - Neither rAF nor rIC are available in Node.js — they're browser-only APIs.
Next: Web APIs #2 — Web Workers & OffscreenCanvas — move heavy computation off the main thread.
