Let’s discuss browser optimization from the rendering level

1. Browser rendering principle and key rendering path

Before exploring browser rendering optimizations, it is essential to understand the browser rendering process, as shown below:

The browser rendering process mainly includes the following steps:

  1. Build a DOM tree: Parse an HTML document from top to bottom to generate a DOM tree (DOM tree; Build the CSSOM(CSS Object Model) tree: Load the parsing style to generate the CSSOM tree;
  2. Construct the render tree: generate the render tree according to the DOM tree and CSSOM tree;
  3. Render tree: A sequence of rectangles displayed on the screen in order, with visual properties such as font, color, and size;
  4. Layout: traverse the rendering tree to start the layout, calculate the location of each node size information;
  5. Painting: Traverse the render tree to paint all nodes, applying the corresponding style to each node.
  6. Composite(multiple layers)

Let’s start with a few questions:

  1. The DOM tree is built when the document is loaded, right?

This is a gradual process. In order to achieve a better user experience, the presentation engine strives to bring content to the screen as quickly as possible. It doesn’t have to wait until the entire HTML document has been parsed to start building the rendering tree and setting up the layout. While receiving and processing the rest of the content from the web, the rendering engine parses and displays some of it.

Reference: taligarsiel.com/Projects/ho…

  1. Is the render tree built after the DOM tree and CSS style tree are built?

In practice, these three processes are not completely independent, but cross. Will cause side loading, side parsing, side rendering work phenomenon.

Reference: www.jianshu.com/p/2d522fc2a…

  1. The more nested CSS tags are, the easier it is to locate elements

CSS is parsed backwards from right to left, and more nesting increases the workload of the browser, not faster.

The original link: blog.csdn.net/riddle1981/…

A few more render blocking issues:

  1. Render block

When the browser encounters a script tag, DOM building is paused until the script completes execution, and then DOM building continues. Every time a JavaScript script is executed, it severely blocks the DOM tree construction. If a JavaScript script also operates on a CSSOM that has not yet been downloaded and built, the browser will even delay script execution and DOM building until its CSSOM has been downloaded and built.

Therefore, the position of the script tag is important. In practice, the following two principles can be followed:

  1. CSS priority: CSS resources are introduced before JavaScript resources.
  2. JS behind: We usually put JS code at the bottom of the page, and JavaScript should affect DOM construction as little as possible.

When parsing HTML, new elements are inserted into the DOM tree, CSS is searched, and the style rules are applied to the elements. The search style sheets are matched from right to left.

For example, div p {font-size: 16px} will look for all p tags and determine whether the parent tag is div before deciding whether to render in this style. So, when we write CSS, try to use ID and class, do not cascade.

  1. Does CSS load block

DOM and CSSOM are usually built in parallel, so CSS loading does not block DOM parsing.

However, since the Render Tree is dependent on the DOM Tree and the CSSOM Tree, he must wait until the CSSOM Tree is built, i.e. the CSS resource is loaded (or the CSS resource fails to load), before he can start rendering.

Therefore, CSS loading blocks Dom rendering.

Because JavaScript manipulates DOM and CSS styles, if you render the interface while modifying these element attributes (that is, the JavaScript thread and the UI thread are running at the same time), the element data obtained before and after the render thread may not be consistent.

So to prevent unexpected results from rendering, the browser sets the GUI rendering thread and JavaScript engine to be mutually exclusive.

As a result, the stylesheet will load and finish execution before the subsequent JS execution, so CSS will block subsequent JS execution

  1. Why does JS block page loading

Because JavaScript is DOM manipulable, if you render the interface while modifying these element attributes (that is, the JavaScript thread and the UI thread are running at the same time), you might get inconsistent element data before and after the render thread.

So to prevent unexpected results from rendering, the browser sets the GUI rendering thread and JavaScript engine to be mutually exclusive.

The GUI thread is suspended while the JavaScript engine is executing, and GUI updates are kept in a queue until the engine thread is idle.

It can be inferred from the above that since GUI rendering threads and JavaScript execution threads are mutually exclusive,

When the browser executes a JavaScript program, the GUI rendering thread is stored in a queue until the JS program completes execution.

Therefore, if the JS execution time is too long, this will cause the page rendering to be inconsistent, resulting in the page rendering load blocking feeling.

Recommend the article

What performance optimization happens from input URL to page rendering — critical path rendering optimization

2. Reflow and redraw

2.1 Process of creating a DOM

  1. Take the DOM and split it into multiple layers
  2. Recalculate style computes the style result for each layer node.
  3. Generate graphics and positions for each node (Layout- Reflux and relayout)
  4. Draw and fill each node into the layer bitmap (Paint Setup and Paint– Redraw)
  5. The layer is uploaded to the GPU as a texture
  6. Match multiple Layers to a page to create the final screen image.

2.2 What is reflow and redraw

Backflow (rearrangement) : When part (or all) of the Render Tree needs to be rebuilt due to changes in element size, layout, hiding, etc. This is called reflow. Backflow is required when the page layout and geometry properties change

Redraw: When some elements in the Render Tree need to be updated with attributes that only affect the appearance and style of the element, not the layout, such as background-color. It’s called redrawing.

It is important to note that backflow always causes redrawing, and redrawing does not necessarily cause backflow.

Common attributes that trigger backflow:

Common attributes that trigger redraw:

Here’s a website to recommend: csstriggers.com

Observe reflux at the console

We can use the developer tools to see if there is layout after the load to determine if backflow has occurred

We can also watch it live online, and by setting this option, the page will turn green when redrawn

2.3 Optimization points of reflux

  1. Replace top with translate
  2. Use opacity instead of visibility
  3. Instead of changing the STYLE of the DOM one by one, pre-define the class and then change the DOM className
  4. Take the DOM offline and modify it, for example: first give the DOM to display: None (once Reflow), then you modify it 100 times before displaying it
  5. Do not place DOM node property values in a loop as variables in the loop, such as offsetHeight. Reading will cause backflow
  6. Do not use the table layout, it is possible that a small change will cause the entire table to be rearranged
  7. Animation implementation speed selection
  8. GIF will trigger redraw frequently, but it is in the tag, so there is no separate layer, we can separate it to make the redraw area smaller
  9. Create a new layer for the animation, but too many layers can also affect performance. Make layers only for the parts that need to be redrawn, and minimize other layers. Will-change: Transform can also create a new layer
  10. Will-change: transform Creates a new layer. What do I do next
  11. Enable GPU hardware acceleration

2.4 Method of creating a new layer

  1. 3D or Perspective Transform CSS properties
  2. Decoded using accelerated video<video>Node, GIF image
  3. Having a 3D (WebGL) context or an accelerated 2D context<canvas>node
  4. Hybrid plug-ins (e.g. Flash)
  5. Animate CSS animations on opacity of its own or use an animated Webkit transform element
  6. An element that has accelerated CSS filters
  7. An element has a descendant node that contains a composite layer (an element has a child element in its own layer)
  8. Element has a sibling element with a lower Z-index that contains a composite layer (in other words, the element is rendered above the composite layer)

3. Avoid layout thrashing

  1. Avoid backflow

We’ve already covered this, so we won’t repeat it here.

  1. Reading and writing separation

We use code to do some reading and writing, as shown below, where the red mark in the upper right corner indicates that the task is too long

We separate read and write operations:

Why read-write separation?

Changing the attributes of a DOM element multiple times does not cause multiple backflow redraws, but rather merges them into one because of the buffering mechanism in the browser. The browser maintains a queue that queues all operations that cause backflow and redraw, and if the number of tasks or time intervals in the queue reaches a threshold, the browser emptying the queue and doing a batch, thereby turning multiple backflow and redraw into one. This is a performance optimization for the browser itself

But when you do a read, the browser clears the queue immediately. Because there may be operations in the queue that affect the return value of these properties or methods, even if the information you want is not related to the change caused by the operation in the queue, the browser will force the queue to empty to make sure you get the most accurate value.

So we separate the read and write operations to avoid triggering multiple backflows.

document.body.addEventListener('click'.function() {
    // Read
    var h1 = element1.clientHeight;
    // Write
    requestAnimationFrame(function() {
        element1.style.height = (h1 * 2) + 'px';) ); );document.body.addEventListener('click'.function() {
    // Read
    var h2 = element2.clientHeight;
    // Write
    requestAnimationFrame(function() {
        element2.style.height = (h2 * 2) + 'px';) ); );Copy the code

In addition, we can use the third-party library FastDom to solve the page jitter

4. Compound threads and layers

Compositor Threads and Layers

What does a composite thread do

  • Split the page layers and draw them and then compound them
  • Use DevTools to learn how to split layers on a web page
  • Which styles affect composition only

5. requestIdleCallback,requestIdleCallback

RequestIdleCallback differs from requestAnimationFrame, which is the start of a frame, and requestIdleCallback, which is the idle time after the end of a frame

How to build a 60FPS app with a frame profile

6. Shake and throttle

7 minutes to understand the throttling, shock prevention and application scenarios of JS

7. Long list optimization

Long list: React-window

  • Loading large lists, each row of a large form, severely affects performance
  • Lazy loading still makes the DOM too large
  • When windowing renders only visible lines, rendering and scrolling performance will improve

A simple, interesting infinite drop-down scheme “front-end advanced” high performance rendering 100,000 data (virtual list) front end of the topic: how to optimize the long list?

Reference article:

Browser rendering process and performance optimization (1.6W word) How browsers Work: Performance Optimization (2017 edition)