Reputation: 8040
Trying to understand RequestAnimationFrame and how it works internally.
Browser has a main thread which is an event loop. The event loop can be populated with various asynchronous events like user interaction, timers getting fired, network calls completing and events triggering layout and painting e.g. input or JS.
So, when a JS function invalidates the layout of the DOM or causes repaint, the browser's main thread repaints the layers that need updating and the compositor thread uploads the updated textures to the GPU where final compositing occurs and the resulting image is displayed onto the screen.
So, I have the impression that browsers only perform paint when actually required. If you capture events on Chrome Dev Tools timeline on a static page with nothing happening, absolutely no events are captured (no layout, no paint, no animation frame fired). Makes sense.
But then you run the following code on the console,
function onBeforeNextRepaint() {
requestAnimationFrame(onBeforeNextRepaint);
console.log('About to paint ...');
}
onBeforeNextRepaint();
Now, you capture the timeline events again and you notice the 'Animation Frame Fired' events and your console gets logged with 'About to paint ...'.
According to MDN,
The Window.requestAnimationFrame() method tells the browser that you wish to perform an animation and requests that the browser call a specified function to update an animation before the next repaint.
That means the browser is constantly painting and therefore calling my function to log the message before each repaint. I am guessing the browsers maintain a scheduler that makes the paint calls at the rate that matches the refresh rate of the screen.
Now my confusion lies on the following:
Upvotes: 13
Views: 11132
Reputation: 23586
The following blog post really helped me understand how the whole thing works.
From it:
Essentially, the whole event loop function can be illustrated with this code:
while (eventLoop.waitForTask()) {
const taskQueue = eventLoop.selectTaskQueue()
if (taskQueue.hasNextTask()) {
taskQueue.processNextTask()
}
const microtaskQueue = eventLoop.microTaskQueue
while (microtaskQueue.hasNextMicrotask()) {
microtaskQueue.processNextMicrotask()
}
if (shouldRender()) {
applyScrollResizeAndCSS()
runAnimationFrames()
render()
}
}
And depict like so:
Upvotes: 16
Reputation: 60517
I think you are misunderstanding the description given by MDN. Let me break it down.
The Window.requestAnimationFrame() method tells the browser that you wish to perform an animation
This means it will tell the browser that you wish to preform an animation that will require repainting. But to do that, we are going to need to run some code.
and requests that the browser call a specified function to update an animation before the next repaint.
This means that just before the next repaint, which the animation would require, call my callback function.
requestAnimationFrame
is not a paint event callback, but a means of firing a callback before the next paint which the browsers must now preform.
Upvotes: 13