What is requestAnimationFrame?

requestAnimationFrame syncs your JavaScript to the display refresh rate. Here's how it works, why it's the right tool for JS animations, and how it differs from setTimeout.

4 min read
JavaScript
Animation
Browser
Fundamentals

TABLE OF CONTENTS
What is requestAnimationFrame?

requestAnimationFrame (rAF) is the browser's API for scheduling JavaScript code to run before the next frame is painted. It's the correct tool for JS-driven visual updates — animations, scroll-linked effects, canvas drawing — because it synchronizes with the display refresh rate rather than running on an arbitrary timer.


How It Works

When you call requestAnimationFrame(callback), the browser queues callback to run just before the next repaint. The callback receives a DOMHighResTimeStamp — the time in milliseconds since the page loaded:

The browser calls your callback once per frame — 60 times per second at 60Hz, 120 times at 120Hz. If the tab is hidden or the page is in the background, the callbacks are paused entirely. This prevents wasted battery and CPU on work the user can't see.


rAF vs setTimeout / setInterval

Using setInterval(fn, 16) for animation is fundamentally broken for three reasons:

1. Doesn't match the display rate. A 60Hz display refreshes every 16.67ms, not 16ms. The mismatch causes tearing — the animation updates between frames, so the screen shows a partially updated state.

2. Runs when the tab is hidden. setInterval keeps firing even when the user is looking at another tab. rAF pauses entirely, saving CPU and battery.

3. No frame budget awareness. setInterval knows nothing about layout, paint, or compositing deadlines. rAF runs at the correct point in the frame lifecycle — after style/layout but before paint.


The Frame Lifecycle

rAF callbacks run at a specific point in each frame:

Because rAF runs before style and layout, it's safe to make DOM changes — the browser will include them in the upcoming frame rather than forcing a mid-frame recalculation.


Cancelling

requestAnimationFrame returns a numeric ID. Pass it to cancelAnimationFrame(id) to stop:

This is equivalent to clearTimeout / clearInterval for timers. Always store the ID if you need to cancel.


When to Use rAF

  • Canvas drawing loops
  • JS-driven animation (when CSS animations aren't flexible enough)
  • Scroll-linked effects (parallax, sticky headers, progress indicators)
  • Batching DOM reads/writes for the next frame

When NOT to Use rAF

  • Simple state transitions — use CSS transitions or @keyframes instead, which run on the compositor thread
  • Non-visual work — use setTimeout or requestIdleCallback
  • Work that must run at an exact interval — rAF adapts to the display rate and pauses when hidden

requestAnimationFrame is the bridge between JavaScript and the browser's frame cycle. If you're animating with JavaScript and not using rAF, you're fighting the display hardware. The API exists precisely so you don't have to.


Let's Connect

© 2026 Naveen Karthik // Built with React & MUI