according to what most articles claims, requestAnimationFrame runs before the browser repaints, and fits in the screen refresh rate. However my understanding is that the browser only repaints when some codes changed what will be on the screen, and the requestAnimationFrame should not be called if nothing happens. I tried this piece of code, it shows that requestAnimationFrame will be called no matter the view changes or not. what part do I understand wrong?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="some">aaa</div>
</body>
<script>
function step(timeStamp) {
console.log("aaa"); // gets printed every frame
window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
</script>
</html>
3
Answers
The only thing you got wrong is that the browser only repaints if something changes. What the articles you read explained is correct:
requestAnimationFrame
matches the user monitor’s refresh rate, meaning that it usually runs 60 times per second.Check MDN’s article for the full details.
requestAnimationFrame
causese the queued function to "run when it can".Calling
requestAnimationFrame
queues upstep
in the event queue so that it will run. If nothing else is executing in the main thread and the queuedstep
is next in line,step
is picked up and executed. But just like any other asynchronous API, when the main thread is busy, queued tasks aren’t picked up until the current task is done. Other things can queue up in the event queue as well (e.g. event handlers, timer callbacks, AJAX callbacks, etc.) so it can be clogged. CallingrequestAnimationFrame(step)
insidestep
queues itself back again.requestAnimationFrame
will also try to match the screen refresh rate, but can slow down if anything takes too long to run between paints (think fps limit instead of vsync).requestAnimationFrame
(and timers in general) can also slow down due to hardware conditions (e.g. running on power saving mode, backgrounded tabs, etc.)Kind of an egg and chicken situation: what if your code in the rAF callback executed something that would need an actual paint?1
The browser doesn’t know that. What it knows is when the window controlled by the monitor’s VSync signal should be open and can accept new paints.
So by "before the next paint", what is meant is before the next time the compositor will push a new frame to the monitor2. Whether they will indeed go into an actual paint or not doesn’t matter. Though note that the simple fact of calling
requestAnimationFrame
will cause at least a Composite Layer operation in Chromium based browsers, even if nothing has changed on screen.See this answer of mine for more details on the matter, and why even an empty rAF may be costly.
1. Which is actually the main purpose of this method.
2. Actually the rendering is double buffered, so it’s when the browser’s compositor sends the frame to the OS compositor.