requestAnimationFrame Scheduling For Nerds

A few people were curious about the scheduling of requestAnimationFrame callbacks, so here’s the tl;dr:

All rAF callbacks always run in the same or next frame of work

Any rAFs queued in your event handlers will be executed in the ​same frame​.
Any rAFs queued in a rAF will be executed in the next frame​.

All rAFs that are queued will be executed in the intended frame.

Let’s say there’s 5 callbacks queued up, and they’ll each take ~100 ms. The browser will not distribute them amongst many frames. It’ll try to run them all in the intended frame, even if it takes 500 ms. That means a pretty significant jank.

You may be asking, “why would there be FIVE animationFrame callbacks requested from within a single frame?” It can accidentally happen if you do 2 very reasonable things. 1) You request a new callback at the end of a rAF. 2) You request rAF callbacks from a input handlers. As a result, you’ve doubled/tripled your work each frame. Youch.

Every rAF you request will run

rAFs aren’t throttled for you if they take too long to execute.

It’s up to you to coalesce rAFs on your own. So: if there’s a chance of multiple of the “same” callbacks firing within the same frame, then you must manage the scheduling/coalescing.

That said, Chrome (at least) will try to help some. If rAFs are hogging the main thread, the browser will start to throttle input events so that, hopefully, the contention will clear up.

And now this.. Two diagrams that (while only slightly related) may illustrate the lifecycle of events in a frame:

Life of a frame (main thread edition)
Event dispatching within a frame

For more implementation details, Sami’s Blink Scheduler talk from BlinkOn 3 is worth a watch, and you can poke around the Scheduler Overhaul resources in ds-hwang‘s Chromium-docs.