7

I'm seeing an excessive paint operation which is taking over 1 second to render in Google Chrome. Is there any way for me to diagnose further what the root cause is? I can see that it's caused by lots of calls to "update layer tree", but I'm not sure where to go from here. The code is just replacing some innerHTML on a single DOM node handled in a scroll event, so I would expect a single recalculate style and then a single paint, why would i see all these update layer tree and separate paint calls?

enter image description here

magritte
  • 7,396
  • 10
  • 59
  • 79
  • A scroll event will trigger many times hence why you are seeing the repaint's so much. You should try looking at throttling or debouncing the function so it is called fewer times. – Matt Derrick Apr 17 '15 at 09:10
  • @MattDerrick I'm already throttling the scroll events, I think the issue is with painting and lots of update layer tree calls causing poor frame rate – magritte Apr 17 '15 at 09:26
  • Depending on what you are changing in the DOM will affect what repaints as well. As an example, I believe if you increase the height of an element and it affects the position of other elements, they will all have to repaint as well. On the other hand, if you increase the height of an element and it's in a container with a fixed height and overflow hidden. No other elements will move therefore will not repaint. – Matt Derrick Apr 17 '15 at 09:31
  • I remember finding this article particularly useful: http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/ Without seeing the code it's very hard to diagnose the issue, repaints and reflows are very funny things at the best of times. I can only assume the repaints are actually other DOM elements that are affected by the single DOM node you are changing! – Matt Derrick Apr 17 '15 at 09:45

1 Answers1

1

You can delay the update on the scroll event by using a so-called debouncing, or, delaying the update until a timeout occur using a timer that is reset every time an event is received:

Example

There is no code shown so this is just a general approach. Implement as needed:

var timerID = null;   // for the timer. must be in parent or global scope

window.addEventListener("scroll", function() {
    clearTimeout(timerID);                // clear current running timer (none is ok!)
    timerID = setTimeout(update, 150);    // set new timer, here with 150ms timeout
});

function update() {
    // do the update here
}
  • Every time the page is scrolled, an scroll event is broadcast and received in the handler.
  • If the timer is still running it will be reset, a new timer invoked.
  • If the scroll event takes more than 150ms (in this case, tweak as needed), the actual update is performed.

This will allow the browser to broadcast a bunch of events without spawning a bunch of updates. In your case the update will affect the DOM tree and paint so it is best to reduce it to an absolute minimum.

Community
  • 1
  • 1
  • Thanks for the response Ken, actually after reading around a bit I think the better way to "debounce" these types of events (scroll, resize) is to set variables which store the state of the window and scroll, and then use a separate render loop using requestAnimationFrame which takes care of the DOM changes. Unfortunately for me it's not helping with the long paint operation so I'm still seeing some "jank". – magritte Apr 25 '15 at 18:29