Author: Ren Jiale

This article is produced by a member of YFE, please respect the original, please contact the public account (ID: yuewen_YFE) for authorization to reprint, and indicate the author, source and link.

preface

Wrote a lengthy report on performance optimization “Checkbox Beautification caused by the Butterfly effect”, lamenting how CSS has so much influence on rendering, maybe the price of deeper memory points is tripping over the same stone twice? Yes, performance optimization “report” second pop up, I hope this article can give you some ideas on optimizing page performance.

What to watch for

Some CSS properties or JS operations that look simple but can easily hide traps?

  • Visibility – To display or hide an element without changing the layout of the document.
  • ClientHeight/clientWidth – Gets the width and height inside the element.

Sharpening the knife is not wrong to cut wood work, performance tools close contact is always essential.

  • How to use the Edge Browser Performance tool
  • How can I quickly locate and resolve performance problems?

How different is the rendering layer from the same browser?

  • How does Edge’s rendering strategy differ from Chrome’s?

Performance of the bomb

The problem began with a “red performance bomb” aimed at the Webnovel “Start Overseas Edition” PC site reading page, keywords: Edge browser, CPU, RAM. A foreign user of Webnovel noted that reading pages on the Edge browser was so CPU intensive that his legs felt the laptop burn.

Webnovel reading page, in order to be closer to the perfect reading experience, we have done: pre-loading the upper and lower chapters, support the upper and lower key switching chapter, no refresh jumping chapter optimization, in the reading process, you will not even see the loading process of content loading. In the face of this performance assault, however, these optimizations are dwarfed by the Edge browser… As for whether the performance optimization is worth it, Google Analytics has the answer:

Webnovel Browser Share overview

Edge browser TOP4 (2.53%) is not negligible! It looks like you’re in for a head-to-head confrontation with Edge, so check out the Edge browser

Analysis of the problem

Before I could locate the problem, something inside me warned me: It was the Google AD script! Not long ago, Google ads were introduced into the reading page, and some logical adjustments were made for the display and hiding of ads. With the purpose, WE started to analyze from JS first.

Search for problem code in performance tools – Google Scripts constantly get clientHeight, clientWidth?

Because Edge only runs on Windows 10, I use an iMac at work, so I hardly use it. I can only go home and “kick” my husband to switch to his desktop dedicated to playing games. The Edge browser version: 42.17134.1.0.

Open the Edge Developer Tool and the performance Tool entry comes into view.

Edge Developer Tools

Get to the point: “Visit the Webnovel Reading page – open the” Performance “TAB – press the Run button.” In order to restore the user’s use scenario, I also carefully scroll through a dozen chapters. Results of the run:

“First Performance Tool Result Graph”

Excuse the color all over the screen. When you see this picture, please promise me that it is a “rendering” problem at first glance, ok? Would you please comment your CSS right away? But I didn’t.

Looking further, you see that there are two subtab bars in the performance tool: the timeline and the JavaScript call stack. The call stack clearly identifies the two items with the highest CPU usage (figure 2), which comes from the OsD.js script for Google ads.

“JavaScript Call Stack for first Performance Tool Result Graph”

Don’t panic. The evidence is not conclusive. The Edge performance tool can actually locate the problem code snippet in JS, right click on the red box area, can also locate the problem source, which is very good! I feel like I’m one step closer to the truth.

“Trace code Problem Detail Map”

“Problem snippet 1”

“Problem snippet 2”

Obviously, the Google osD. js script sets a timer that continuously fetches the clientWidth and clientHeight of the HTML node, so the root of the problem is this?

Some hidden dangers of clientHeight and clientWidth

Facebook engineer Stoyan mentioned in his blog that the browser is smart. In order to save resources and not trigger Repaint or Reflow frequently, it will queue up a series of UI changes that need to be executed in a script. Instead of each change being executed individually and causing countless Repaint, Reflow, etc. BUT!!! There are a few operations that disrupt its original plan and order:

  1. OffsetWidth, offsetHeight, offsetTop, offsetLeft
  2. ScrollTop, scrollLeft, scrollWidth, scrollHeight
  3. ClientlTop, clientLeft, clientWidth, clientHeight
  4. GetComputedStyle (), or currentStyle in IE

The browser gives the most accurate real-time answers to these actions “in a very timely manner,” thus triggering Reflow, such as recalculating styles, updating layers, and so on. Keep in mind that Reflow has more impact and wear on rendering than Repaint.

Demo Time – Will fetching clientWidth trigger unnecessary rendering?

Function Description:

  1. After page onload, set a timer to get the clientWidth of the HTML node every 4ms (the browser’s default minimum interval).
  2. Click the Click Me button to horizontally shift Box1 to the far right.
  3. Click the No Timer button to clear the timer while horizontally shifting Box1 to its original position.

“Demo GIF”

process

The results of

Stage 1: Before “Click Me”

Render events such as Reflow are not triggered

Stage 2: After “Click Me”

Trigger additional rendering (Recalculate style, Update Layers)

Stage 3: After “No timer”

Render events such as Reflow are not triggered

The Chrome Performance tool more visually describes the results in the table (stage two in the red box clearly shows the additional rendering) :

To highlight the difference, I increased the number of divs that moved horizontally to 20, and the Recalculate Style data was off by 70ms:

“Render data difference: Get clientWidth during animation (top), do nothing during animation (bottom)”

Demo results verify that in Chrome, fetching clientWidth/clientHeight during animation does cause Reflow in the browser, and this effect only gets worse as animation complexity and elements increase, thus increasing unnecessary rendering consumption.

First attempt – remove Google ads

Since the CPU spike in reading pages is most likely due to Google’s osD.js fetching clientWidth/clientHeight of HTML nodes accidentally triggering multiple reflows, the first step to solve the problem is to remove Google ads. I used the Fiddler proxy JS script locally to remove the ad-related code.

But it turned out to be completely different from what I thought. Removing the ads didn’t make the page perform any better. Is it really not Google ads?

Again – Google ads on other sites have similar problems

I continued to test a similar site with the Edge performance tool, because the site also uses Google ads and loads four ads simultaneously on its home page, compared to the first one AD initialized on the Webnovel reading page. However, there are no rendering problems (see below), and the CPU utilization section of the site is not even green at all.

Flip the script and switch direction to CSS

Too much faith in your vision can lead you astray? In the early days, I was too convinced that Google AD scripts were the problem. Since the above two attempts proved not to be the problem of Google AD scripts, it was time to change direction.

I was inspired to write about the butterfly effect of Checkbox beautification: CSS has a greater impact on rendering performance than JS. Combined with the demo conclusion mentioned above, it is tempting to speculate that the performance problems of reading pages may be due to some CSS properties or animations interacting with clientHeight and clientWidth in Google AD scripts, causing additional rendering. At this point, I tried to comment out all the styles, and eventually the green color disappeared, indicating that it was most likely the CSS pot.

“Missing render in CPU usage”

The culprit is visibility: hidden?

Continue to look for more precise answers from the performance tools, and find a lot of useful information captured in the “Timeline” TAB of the Edge performance tools, and even find style related items? It’s awesome to expand to locate the DOM that’s currently causing the rendering!

This helped a lot in locating the problem because I could clearly see the DOM in question, the loading component we wrote.

Indeed, there are several hidden loading on the reading page of Webnovel, which exist in the chapter and comment pop-up window, the directory pop-up window, and between the contents of each chapter.

“Chapter and Comment popover, Directory popover”

“Loading between chapters”

Hiding loading is to simplify logic. It can be “ambushing” where it is needed. Before obtaining asynchronous data, loading can be shown to users at the first time. So why does hidden loading affect rendering? Loading in the popup of the Webnovel reading page is hidden by using visibility: hidden.

Visibility: hidden has both advantages and disadvantages

Can you see no trace of loading, but it still has such a big impact on rendering? You think you are hiding the loading correctly, but the loading actually exists in the document flow, and each animation of it affects the other nodes in the document flow.

  • Visibility: hidden // DOM will not be rendered ignoring all its nodes
  • Display: None // DOM rendering ignores all of its nodes

In this case, better performance would be display: None, which does not affect other elements if it is not in the document flow. But every CSS property that has been created must have been created for a reason. If display: None is the most recommended method, why undefined: hidden? Every coin has two sides, for example, in the following scenario, Visibility: Hidden helps a god solve a performance problem.

In his blog “Solving Rendering Performance Puzzles,” Google engineer Jake Archibald used an interesting SVG animation to verify the importance of layouts in web performance. As the SVG text in the animation continued to change, the frame rate of the animation eventually dropped from an optimal 60fps to less than 10fps. Chrome’s Performance tool reveals that the main factor is that it generates a lot of Layout Thrashing or Reflow.

Jake uses the visibility: hidden element to solve the problem of too much Layout consumption. He says that the element visibility: hidden, because it occupies a place in the document flow, is set to be undefined: Visible does not consume Layout, only extra paint. With this in mind, he places all the characters in SVG separately into the child <tspan> of the < textPath > node and uses visibility: Hidden To conceal:

“SVG text hidden in the DOM”

Then change <tspan> to visible, and the characters will be displayed in turn. By contrast, his original method is really very rude, that is: Store all characters in a single node, each time a fixed length of text is intercepted, set to the value of <textPath>. The massive resetting of textPath node values eventually caused a per-character relayout of the browser.

Therefore, it can not be concluded that the visibility: hidden is not as good as or better than display: none, but that they have their own advantages in different scenarios.

Problem fix

Obviously, hiding the loading animation with visibility: Hidden does incur a lot of additional rendering overhead. There are many solutions to fix this problem. For example, you can change the hiding mode of loading to display: None, or loading was added to the DOM in real time when the popover was opened. In order to avoid the global impact of changing the CSS of the dynamic window component, we added the LOADING DOM node when the popover was opened, and removed it when the popover was closed. User feedback after a week also proves that the solution works (figure below).

“User Feedback”

An attempt at a new scheme

How does Edge render differently than Chrome?

The Webnovel page reading problem has been resolved, but we may all be wondering why this performance problem doesn’t occur or is not evident in Chrome. Here I’ve done a wave of testing with Jake’s SVG animation mentioned in the section “Visibility: Hidden”. The performance tool did a quick check and found that animations without optimization performed just as badly as Chrome:

“Edge Browser Performance Results”

The optimized animations also don’t perform as well as Chrome’s. Visually, as this GIF shows, animations on Edge (second image) are much slower than on Chrome (first image).

“Up Chrome, down Edge”

As shown in Chrome Performance, Jake’s optimization strategy has reduced the consumption of Layout from TOP3 to bottom:

“Before optimization, after optimization”

But the results of the Edge performance tool were not even as good as before, with no reduction in rendering and lots of CPU shocks on JS (orange area) :

“Pre-optimization”

“After optimization”

The overhead of the optimized rendering layer is even greater than the overhead before optimization (when the animation runs for about the same length of time) :

“Optimize before and after UI thread Data”

In this demo, Edge renders SVG animations exactly the opposite of Chrome. More importantly, Chrome seems to have a different tradeoff between Layout and Paint performance. While reducing a lot of Layout overhead does make for smoother animations in Chrome, it doesn’t work on Edge, or vice versa.

New ideas for problem solving

The difference in the performance of SVG animation between Chrome and Edge gives me some new ideas. Back to the Webnovel page, we do use a lot of SVG in our pages. I try to display SVG: When inline-block was changed to display: None, the CPU was quickly lowered and performance improved (see figure below).

“Before Commenting on SVG Styles”

“After Annotating the SVG Style”

However, the performance problem has been solved, and all Webnovel stations use SVG, it would be rude to replace SVG globally at this time, and Jake’s demo is not enough to show that too much SVG affects the performance of the page, so the scheme is not implemented. But it does serve as another breakthrough for the Reading page performance problem of the Webnovel, and it will take more time to explore this mystery.

A little chatter

Of course, fixing problems always requires a summary:

  • Visibility: Hidden is a double-edged sword.
  • Operations such as clientWidth and clientHeight are not recommended during animation.
  • If a performance tool shows massive green bloating, be sure to comment your CSS first to see what’s going on
  • Unable to locate the problem can be compared to other similar sites to get inspiration, so as to further locate
  • It’s important to note that the Edge browser renders slightly differently than Chrome.

Performance optimization this is a positive attempt and dare to the process of trial and error, is the so-called yongxing that thousands of miles, not a little accumulation and exploration to output “n” best performance optimization solution, it is better to refine positioning problem of ideas, extend the cognitive range, at the same time formed a kind of attitude towards the performance bottleneck will not fear, Hopefully we can all smile in the face of performance bottlenecks.


Refer to the link

  • Developers.google.com/speed/docs/… “Google Developer Documentation – Browser Rearrangement Behavior”
  • Jakearchibald.com/2013/solvin… “Jake Archibald – Solving Rendering Performance Issues”
  • Developers.google.com/web/tools/c… “Google Developer Documentation – Analyzing runtime Performance with Rendering Tools”
  • www.w3cplus.com/animation/a… “CSS Animation Performance Optimization”


For more sharing, please pay attention to the front end team official account of China Literature Group: