Why is it recommend to nest setTimeout in requestAnimationFrame when scheduling something after a repaint?
Asked Answered
P

1

11

In the mozilla docs on performance best practices for front-end engineers it's recommended to combine setTimeout with requestAnimationFrame to run something immediately after a repaint:

requestAnimationFrame(() => {
  setTimeout(() => {
    // This code will be run ASAP after Style and Layout information have
    // been calculated and the paint has occurred. Unless something else
    // has dirtied the DOM very early, querying for style and layout information
    // here should be cheap.
  }, 0);
});

Why is this the recommended solution? What exactly makes this the optimal way to schedule something right after a repaint?

Provo answered 8/11, 2017 at 16:3 Comment(2)
The DOM is not recalculated whe you set new (layout)values to it, the recalculation occurs when you read values after changing the DOM, or just before it is repainted. The timed function gives you most likely an unchanged DOM, i.e. it is readily calculated, and reading a value doesn't cause recalculation, because the timed function will be called immediately after the repaint.Botsford
"querying for style and layout information here should be cheap." no page re-flow, calculation, etc...Shiksa
P
8

Why is this the recommended solution? What exactly makes this the optimal way to schedule something right after a repaint?

Running code immediately after a repaint maximizes the chance that the DOM has been fully calculated, and thus minimizes the chance that querying the dom will cause a costly reflow. If you're not querying the dom anyway, then this isn't something you need to worry about.

requestAnimationFrame will schedule code to run immediately before the repaint, which is close to where you want to be but not quite. So then doing a setTimeout of 0 (or setImmediate on browsers that support it) will execute code as soon as it can after that. This won't guarantee that your code is the first thing to run after the repaint, but it's the best you can do given the apis at your disposal.

Peachey answered 8/11, 2017 at 16:8 Comment(9)
You say that requestAnimationFrame will schedule code to run immediately before the repaint, but it might call the provided callback multiple times in the same frame right? How can it call the cb multiple times in the same frame and still guarantee to run right before repaint?Provo
if you only call requestAnimationFrame once, then you should only get one callback.Peachey
Yeah but if you recursively call it.Provo
If you're in a requestAnimationFrame callback and you make another call to requestAnimationFrame, that second call will happen on the next frame, not the current one.Peachey
Well mdn states: Multiple callbacks in a single frame, therefore, each receive the same timestamp even though time has passed during the computation of every previous callback's workload. developer.mozilla.org/en-US/docs/Web/API/window/…Provo
That's relevant if you make multiple calls to requestAnimationFrame all before the frame goes off. Making a call to requestAnimationFrame while inside a requrestAnimationFrame callback should not cause this.Peachey
I understand that as: the callback might be called multiple times in the same frame, if you recursively call requestAnimationFrame. Or am I misunderstanding? Because in that case how can execution right before repaint be guaranteed?Provo
As i said, calling requestAnimationFrame while inside a requestAnimationFrame callback will wait until the next frame. You will only get callbacks one at a time.Peachey
Ah ok, I understand now. They're talking about calling requestAnimationFrame multiple times, but not when inside the callback. Just multiple unrelated calls. Thanks for explaining, it makes sense now.Provo

© 2022 - 2024 — McMap. All rights reserved.