-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
140: Using requestAnimationFrame Effectively
Imagine you're running an old-school film projector. The machine has a shutter that opens and closes at a very precise rhythm—say, 24 times a second. If you try to slide a new frame of film into place whenever you feel like it, regardless of where the shutter is, you'll get a jittery, flickering mess. The image will tear, or you'll skip frames entirely. To get that buttery-smooth cinematic motion, you have to time your frame swaps exactly to the beat of the projector's shutter.
In the browser, the "shutter" is the display refresh rate (usually 60Hz, though it varies on modern monitors). When you use setInterval or setTimeout for animations, you're essentially guessing when the shutter is open. You might push an update just after the browser has already repainted the screen, meaning your update sits there doing nothing until the next cycle. That's where "jank" comes from. requestAnimationFrame (or rAF) is your way of telling the browser, "I have an update ready; please execute it exactly when you're about to paint the next frame."
Stopping the Fight with the Browser's Heartbeat
The biggest win with rAF isn't just smoothness—it's efficiency. I've seen countless apps chew through laptop batteries because they were running setInterval loops in background tabs. The browser is smart; if a tab is hidden, it stops calling requestAnimationFrame. Your animation effectively pauses, saving the user's CPU and battery without you having to write a single line of "tab-visibility" logic.
Here is the basic pattern. Notice how the function calls itself recursively, but only when the browser is ready:
const box = document.querySelector('.box');
let position = 0;
function update() {
position += 2;
box.style.transform = `translateX(${position}px)`;
// We ask the browser to call this again before the next repaint
requestAnimationFrame(update);
}
// Start the loop
requestAnimationFrame(update);
The Trap of the Fixed Increment
Look closely at the code above. I'm adding 2px every frame. On a standard 60Hz monitor, that box moves at a predictable speed. But what happens if your user has a 144Hz gaming monitor? The update function will run more than twice as often, and that box will suddenly scream across the screen at double speed. I've seen this bug ruin "smooth" UI transitions on high-end hardware.
To fix this, we use the timestamp that rAF automatically passes to your callback. This allows us to calculate movement based on actual time elapsed rather than frames passed. This is called "frame-rate independence."
let start = null;
const distance = 500; // Move 500px total
const duration = 2000; // Over 2 seconds
function animate(timestamp) {
if (!start) start = timestamp;
// Calculate how much time has passed since we started
const elapsed = timestamp - start;
// Calculate progress as a decimal between 0 and 1
const progress = Math.min(elapsed / duration, 1);
const currentPos = progress * distance;
box.style.transform = `translateX(${currentPos}px)`;
if (progress < 1) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
When to Actually Use This
I'll be honest: you don't always need rAF. If you're just moving a sidebar in and out, a CSS transition or animation is almost always better because the browser handles those on a separate compositor thread. Use requestAnimationFrame when you're doing something a CSS transition can't handle—like complex physics, canvas drawing, or an element whose destination changes dynamically based on user input (like a custom cursor or a drag-and-drop interface).
📋 Practical Task
Exercise: Building a Frame-Rate Independent Bouncing Orb
Your goal is to create a smooth animation of a circle bouncing horizontally across the screen. However, the orb must move at the exact same speed regardless of whether the user's monitor is 60Hz, 120Hz, or 144Hz.
- Create a
divwith the class.orb(style it as a circle with a fixed width/height). - Use
requestAnimationFrameto animate the orb from the left side of the screen to the right and back again. - Requirement: Instead of adding a fixed number of pixels per frame, calculate the position using the
timestampargument. The orb should take exactly 3 seconds to travel from one side to the other. - Requirement: Ensure the animation loops indefinitely.
There are no comments for now.