Search code examples
javascriptevent-looprequestanimationframe

Which queue is associated with requestAnimationFrame?


Today I was asked this question on an interview. I couldn't answer this question and the interviewer said there was a special queue for requestAnimationFrame callbacks. But I can't find any information on this.

If rAF has it's own queue then why is this queue never mentioned anywhere? We only mention macro- and microtask queues when we talk about Event Loop?


Solution

  • We only mention macro- and microtask queues when we talk about Event Loop?

    First, there is no mention of "macro" task in the specs, only tasks and microtasks (and then callbacks, more on that later).

    Then, almost every task source have their own task queues in modern browsers, though they currently don't have to. So there isn't just two queues, one that would be the microtask queue and another one for all the tasks, there are a lot of task queues (each MessagePort instance can have its own task queue). This allows to have various priority for each task source. So that UI events can get treated before network ones, for instance.

    But requestAnimationFrame callbacks are not even queued in a task queue. This method schedules a callback that (in the specs1) isn't invoked from a task, but from a special place in the event loop called "update the rendering", itself visited only once in a while (generally when the monitor sends a VSync signal and the document is active), which will also fire scroll and resize events, Web Animation updates, ResizeObserver callbacks, etc. and the rendering of the page.

    This is important that conceptually all these steps are not executed in a tasks, because this means that any task queued from these callbacks will not get executed before the next rendering, while still ensuring that a ResizeObserver callback scheduled from a resize event for instance, will be called before.

    Animation frame callbacks are stored in an ordered map, called the map of animation frame callbacks. It's not a queue per-se, since we can "cancel" the callbacks through the cancelAnimationFrame() method. Also this allows getting all the keys at the beginning of the run the animation frame callbacks algorithm which itself allows to schedule new callbacks from such a callback to the next animation frame without blocking the event loop forever (if it were a queue, the algorithm would keep calling new callbacks endlessly, like it does in the microtask checkpoint).

    But that much details is a bit pedantic and unless you're really into this kind of stuff you shouldn't need to know more than

    • most native events and Web API callbacks are queued in task queues, which get visited at the beginning of the event loop with a prioritization system,
    • all microtasks are executed every time after a callback has been invoked, in a way you can stuck the event loop if queuing microtasks from a microtask,
    • some render-related native events and animation frames are treated in their own place in the event loop.

    Still, I believe it's good to understand that there is this special update the rendering step in the event loop, that is distinct from the other queued tasks in that it doesn't participate in the task prioritization system. I often read that it has an higher priority but IMO it's wrong to say that and given we'll soon have true control over some tasks prioritization, it will grow more important. It also helps understand when the styles recalc are performed and the relationship with (synchronous) DOM updates, and other stuff related to the rendering in a browser. But if you're not applying to a position that involves the details of browser rendering, maybe they just expected the (IMO pretty bad and) colloquial "in the render queue", as is being used e.g. in P.Roberts's Loupe.

    1: Firefox, for one, actually queues tasks even for these, but they do it in a way it's not observable.