Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Request animation frame called constantly

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 ...'.

onBeforeNextRepaint gets called

Animation Frame Fired invoked

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:

  1. Is the browser's main thread constantly repainting, generating textures and uploading textures to the GPU and making draw calls (throttled to match the refresh rate of the screen)? (Sounds inefficient)
  2. Is that the reason why my 'onBeforeNextRepaint' callback gets called constantly?
  3. If 1 and 2 are true, on my first timeline capture, why do i not capture 'Update Layer Trees' and 'Composite Layers' events?
like image 609
Prashant Avatar asked Feb 21 '15 18:02

Prashant


People also ask

How often is request animation frame called?

The number of callbacks is usually 60 times per second, but will generally match the display refresh rate in most web browsers as per W3C recommendation. requestAnimationFrame() calls are paused in most browsers when running in background tabs or hidden <iframe> s in order to improve performance and battery life.

Should I use request animation frame?

To optimize system and browser resources, it is recommended to use requestAnimationFrame , which requests the browser to execute the code during the next repaint cycle. This allows the system to optimize resources and frame-rate to reduce unnecessary reflow/repaint calls.

What is animation frame?

The frame is a single image in a sequence of pictures. In general, one second of a video is comprised of 24 or 30 frames per second also known as FPS. The frame is a combination of the image and the time of the image when exposed to the view. An extract of frames in a row makes the animation.

How do I stop requestAnimationFrame?

If you assign your requestAnimationFrame() method to a variable, you can use the cancelAnimationFrame() method to cancel it before it runs.


2 Answers

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.

like image 64
Alexander O'Mara Avatar answered Sep 30 '22 16:09

Alexander O'Mara


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:

A diagram showing the task/microtask/and animationframe queue

like image 29
Izhaki Avatar answered Sep 30 '22 17:09

Izhaki