Frontend Development 8 min read

How requestAnimationFrame Works Under the Hood in Chrome: A Deep Dive

This article explains the inner workings of requestAnimationFrame, detailing why setTimeout/setInterval fall short, how Chrome's animation controller registers and fires callbacks, and the call stack that drives frame updates, complete with code excerpts and diagrams.

Taobao Frontend Technology
Taobao Frontend Technology
Taobao Frontend Technology
How requestAnimationFrame Works Under the Hood in Chrome: A Deep Dive

Most developers now use

requestAnimationFrame

for JavaScript animations, but before its introduction the only options were

setTimeout

or

setInterval

, which suffer from timing inaccuracies, over‑rendering, and lack of synchronization with the browser’s rendering loop.

The core issue is timing:

setTimeout

and

setInterval

provide fixed‑interval timers without knowledge of when the browser is ready to render the next frame. The browser, however, can determine the optimal moment for a new frame, and

requestAnimationFrame

bridges this gap by letting the engine schedule callbacks at the right time.

In Chrome (based on Android 4.4), the implementation is surprisingly simple. When a script calls

requestAnimationFrame(callback)

, the engine creates a

ScriptedAnimationController

instance and registers the callback:

<code>int Document::requestAnimationFrame(PassRefPtr&lt;RequestAnimationFrameCallback&gt; callback)</code>

The controller stores callbacks, checks that the page is visible, and ensures they are only executed on the next animation frame. It also guards against background tabs:

<code>if (!page()) return;
view->serviceScriptedAnimations(monotonicFrameBeginTime);</code>

When the browser is ready to paint a new frame, it walks a call stack that eventually reaches

PageWidgetDelegate::animate

or

WebViewImpl::animate

. These functions invoke

serviceScriptedAnimations

, which iterates over the pending callbacks, converts the high‑resolution time to the appropriate base (legacy or modern), and calls each callback’s

handleEvent

method.

After callbacks run, the controller removes any that have fired or been cancelled and, if more callbacks remain, schedules another animation frame. The scheduling logic uses

base::Time

and

base::TimeDelta

to target 60 FPS when vsync is enabled, otherwise it runs as fast as possible.

Key steps of the mechanism are:

Register the callback with

requestAnimationFrame

.

The browser’s render loop triggers

animate

during a frame update.

animate

calls the controller, which executes all registered callbacks.

This ownership transfer of frame timing to the browser kernel synchronizes animation updates with rendering, avoids desynchronization, and gives the browser room to optimize.

Various entry points such as

RenderWidget::didInvalidateRect

or

RenderWidget::CompleteInit

can request an animation check, ensuring that any change that might affect the visual output schedules a new frame.

The following diagram (from the official spec) illustrates the overall flow of

requestAnimationFrame

:

requestAnimationFrame implementation diagram
requestAnimationFrame implementation diagram
Note: RenderWidget lives in content/renderer/render_widget.cc , not in core/rendering/RenderWidget.cpp . The author was initially confused because the latter contains no animation code.

In summary,

requestAnimationFrame

works by delegating the timing of animation callbacks to the browser’s rendering engine, which registers callbacks, fires them at the optimal moment, and reschedules as needed, providing smoother and more efficient animations than traditional timers.

Unsplash illustration
Unsplash illustration
JavaScriptChromeanimation timingrequestAnimationFramebrowser animation
Taobao Frontend Technology
Written by

Taobao Frontend Technology

The frontend landscape is constantly evolving, with rapid innovations across familiar languages. Like us, your understanding of the frontend is continually refreshed. Join us on Taobao, a vibrant, all‑encompassing platform, to uncover limitless potential.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.