The Event Loop, Visualized

requestAnimationFrame vs setTimeout — interactive event loop example

1console.log('start');
2
3setTimeout(() => {
4 console.log('timeout');
5}, 0);
6
7requestAnimationFrame(() => {
8 console.log('rAF — right before paint');
9});
10
11Promise.resolve().then(() => console.log('promise'));

The script runs on the call stack. console.log("start") executes synchronously.

1 / 10

Call stack

script

Web APIs — browser land

The event loop — is the call stack empty? → drain the microtask queue first → then take one callback.

Microtask queue — priority

Callback queue

Console

01start

Fig. — requestAnimationFrame vs setTimeout · step 1 of 10

What is going on here

requestAnimationFrame is not a queue you have met so far. It is neither a task nor a microtask: the callback goes on the document's animation frame list, and the browser services that list during its render step — after the current task and its microtask checkpoint, immediately before style, layout and paint.

That placement is the entire reason to use it for animation. Any DOM mutation made inside a rAF callback is painted in that same frame, so movement lands on the display exactly once per refresh with no extra frame of latency. It also means rAF runs at the display's rate, usually about every 16.7ms, and pauses entirely on a background tab, whereas setTimeout keeps firing (throttled) at whatever interval you named.

Animating with setTimeout(fn, 16) instead is the classic mistake. Your timer does not align to the refresh cycle, so some frames get two updates and some get none — visible as stutter. The ordering shown here also holds in general: microtasks first, then a task, and rendering only when the browser decides a frame is due, which is not after every single task.

Common questions

Is requestAnimationFrame a macrotask or a microtask?

Neither. Animation frame callbacks live on their own list and are run by the rendering step of the event loop, after the current task and its microtask checkpoint but before paint.

Should I use requestAnimationFrame or setTimeout for animation?

Use requestAnimationFrame. It synchronises with the display refresh rate so each visual change is painted exactly once per frame, and it pauses in background tabs instead of burning cycles.

Does the browser render after every task?

No. Rendering is a separate step the browser performs when a frame is due, typically about sixty times a second. Several tasks can run between two paints, and if a task runs long the frame is simply missed.

Every question on one page →·Run your own code →

Embed this figure in your own post →

Drop this into any article or course page. It stays interactive — readers can step through it without leaving your site.