Performanceintermediate
requestAnimationFrame and Smooth Animations
A browser API for scheduling visual updates in sync with the display's refresh cycle, producing smoother animations than setTimeout-based approaches.
requestAnimationFrame schedules a callback to run just before the next repaint, in step with the display.
requestAnimationFrame is like a stagehand who only makes their next scenery change exactly when the curtain is about to rise for the next scene, perfectly timed to the actual show's pacing — versus a stagehand on a fixed independent stopwatch (setTimeout) who might make changes mid-scene, out of sync with what the audience is actually about to see, wasting effort or causing visible jank either way.
Key Concepts
1
function animate() {
element.style.transform = `translateX(${x}px)`;
x += 2;
if (x < 300) requestAnimationFrame(animate);
}
requestAnimationFrame(animate);translateX(${x}px)
2
Against setInterval(fn, 16).
setInterval a timer that drifts against the refresh rate.
Frames get skipped or doubled.
rAF once per frame, whatever the rate --
60 Hz, 120 Hz, or variable.setInterval(fn, 16)
3
rAF also pauses when the tab is hidden. An interval keeps running and keeps draining the battery.
rAF
4
The timestamp is the argument. Using it is what makes an animation frame-rate independent:
5
let last = 0;
function animate(now) {
const dt = now - last; // ms since the last frame
last = now;
x += speed * dt; // distance per millisecond
element.style.transform = `translateX(${x}px)`;
requestAnimationFrame(animate);
}translateX(${x}px)
6
Without it, movement is per frame. So the animation runs twice as fast on a 120 Hz display as on a 60 Hz
one.
7
Animate the cheap properties.
transform, opacity compositor only -- no layout, no paint
left, top, width layout on every frame8
That distinction decides whether an animation is smooth. It matters more than anything else here.
9
One frame is 16.7 ms at 60 Hz, and the browser's own work comes out of that. A callback taking 10 ms
leaves very little, and the frame is dropped.
10
Use it to batch DOM writes, not only for animation:
11
let pending = false;
window.addEventListener('scroll', () => {
if (pending) return;
pending = true;
requestAnimationFrame(() => { updateHeader(); pending = false; });
});12
Scroll fires far more often than the screen refreshes. This collapses many events into one update per
frame, which is often better than throttling by time.
13
And when CSS is the right answer. A transition or a keyframe animation runs on the compositor with no
JavaScript at all.
14
Use rAF when the values are computed — physics, gestures, canvas. Use CSS when the animation is
declarative.
rAF
15
What the interviewer is probing.1. "Why use rAF instead of setInterval for animation?" Probing: the sync. Stalls: "It is
newer." Moves up: it runs just before the next paint and matches the display refresh, so frames
are not dropped or doubled, and it pauses in background tabs.
16
2. "How do you make animation frame-rate independent?" Probing: the technique. Stalls:
"Fixed increments." Moves up: use the timestamp passed to the callback to compute elapsed time and
scale movement by it.
17
3. "Which properties should you animate?" Probing: the compositor. Stalls: "Any." *Moves
up:* transform and opacity, which the compositor handles without layout or paint.
18
4. "How do you stop an animation?" Probing: cleanup. Stalls: "It stops." Moves up: keep
the id and call cancelAnimationFrame, especially when a component unmounts.