How to Fix requestAnimationFrame Stuttering in JavaScript
In this tutorial, you'll learn about How to Fix requestAnimationFrame Stuttering in JavaScript. We cover key concepts, practical examples, and best practices.
The Problem
requestAnimationFrame animations stutter or jank when a single frame takes longer than 16ms (60 FPS), causing dropped frames and uneven animation pacing.
Quick Fix
Step 1: Use delta time for consistent speed
Frame rates vary, so advance animations by elapsed time, not fixed increments:
let position = 0;
function animate() {
position += 1;
element.style.transform = `translateX(${position}px)`;
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
This runs at different speeds on different monitors. Use delta time:
let position = 0;
let lastTime = 0;
function animate(timestamp) {
const delta = lastTime ? (timestamp - lastTime) / 16.67 : 1;
lastTime = timestamp;
position += 1 * delta;
element.style.transform = `translateX(${position}px)`;
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
Step 2: Avoid layout thrashing
Reading layout properties forces synchronous style recalculation:
function animate() {
elements.forEach(el => {
const width = el.offsetWidth;
el.style.width = (width + 1) + 'px';
});
requestAnimationFrame(animate);
}
Batch reads before writes:
function animate() {
const widths = elements.map(el => el.offsetWidth);
elements.forEach((el, i) => {
el.style.width = (widths[i] + 1) + 'px';
});
requestAnimationFrame(animate);
}
Step 3: Reduce DOM operations
Move heavy work outside the animation loop:
function animate() {
const result = expensiveCalculation();
element.style.transform = `translateX(${result}px)`;
requestAnimationFrame(animate);
}
Cache calculations and use compositor-only properties:
function animate() {
element.style.transform = `translateX(${position}px)`;
position += 1;
requestAnimationFrame(animate);
}
Use transform and opacity only, as these are composited on the GPU.
Step 4: Use will-change hint
Hint the browser about what will change:
.animated-element {
will-change: transform, opacity;
}
Prevention
- Use delta-time calculations for frame-rate-independent animation.
- Batch DOM reads before writes (fast path).
- Animate only
transformandopacityproperties. - Keep animation work under 16ms per frame.
- Use
will-changesparingly on elements that animate continuously.
Common Mistakes with requestanimationframe
- Using
foldlinstead offoldl'causing stack overflow on large lists - Forgetting
deriving (Show, Eq)on custom data types needed for debugging - Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
These mistakes appear frequently in real-world JS code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro