Chrome Performance looks at the browser rendering process

Let’s start with a very simple page code

<! Doctyehtml>
<html>
<head>
</head>
<body>
  <div> 
    Test dom load.
  </div>
</body>
</html>
Copy the code

Then open Chrome Performence to see how the page is rendered:

  • Send Request: Triggered when a network Request is sent
  • Receive Response: Triggered when the Response header packet arrives
  • Receive Data: The arrival event of the response Data for the request, which may be triggered multiple times if the response Data is large (unpacked)
  • Finish Loading: Indicates the event that the network request ends
  • Parse HTML: The browser performs HTML parsing
  • Update Layer Tree: Updates the Layer Tree.
  • Paint: After determining the size and position of the nodes in the render tree, you can Paint the nodes (Paint)
  • Composite Layers: When the nodes in the rendering tree are painted, a bitmap is generated. The browser transfers this bitmap from the CPU to the GPU

Parse Html (without CSS and JS)


<! Doctyehtml>
<html>
<head>
</head>
<body>
  <div class='div'> 
    Test dom load.
  </div>
  <script type="text/javascript">
    console.log('resolve body JavaScript');
   
    window.addEventListener('load'.function(){
      console.log('window load');
    })

    document.addEventListener('readystatechange'.function(){
      console.log('document ' + document.readyState);
    })

    document.addEventListener('DOMContentLoaded'.function(){
      console.log('document DOMContentLoaded');
    })
    //document has no load event?
    document.addEventListener('load'.function(){
      console.log('document load');
    })
  </script>
</body>
</html>

Copy the code

Let’s take a look at it from left to right in the timeline:

Readystatechange (first)

DOM readyStatechange. The readyState property describes the loading state of the document. Document. readyState changes throughout the loading process. Each change triggers the readyStatechange event.

ReadyState has the following states:

  • Loading loading document is still loading.
  • The document has been loaded, the document has been parsed, but sub-resources such as images, stylesheets, and frames are still loading.
  • The DOM document and all child resources are loaded. Status Indicates that the LOAD event is about to be triggered.

So what step does the event perform here?

Interactive is implemented here. Because this event is followed by the DOMContentLoaded event, and if you go to this page to see for yourself, there is also a readyStatechange in front of parseHtml, which should be loading.

DOMContentLoaded

The DOMContentLoaded event is triggered when the DOM tree rendering is complete, possibly while the external resource is still loading. This indicates that the DOM tree is loaded.

Recalculate Style (build CSSOM tree)

The literal sense of the word means recalculating the style. Why re-caculate Style? This is because the browser itself has the User Agent StyleSheet, so the resulting style is overridden/recalculated by our style code style and the User Agent default style. This is also building the CSSOM tree.

Readystatechange (second)

As you can see from the first event, complete is executed, indicating that the DOM and CSSOM trees on the page have been formed and merged into the Render tree. All resources on the page have been loaded. You can see this from the load event

The load event

The Window load event is triggered when all resources are loaded.

Pageshow events

A pagesHow event is triggered when a session history is executed. This includes the back/forward button action, which is also triggered when the page is initialized after the Load event is triggered.

The following example will print the PagesHow event on the console triggered by the forward/back button and the Load event:

window.addEventListener('pageshow'.function(event) {
    console.log('pageshow:');
    console.log(event);
});
Layout
Copy the code

Layout

Will render the node in the tree, according to its height, width, position, generate boxes for the node. Add a box model for the element. In the figure above, there are two layouts. The difference between the two layouts is Nodes That Need layout 1/5 of 5. Here, 5 represents 5 Nodes on the page (text content is text node). After all, it belongs to Layout.

Let’s think about what ParseHtml does: build the DOM tree -> build the CSSOM tree -> build the Render tree -> Layout

Parse Html (with CSS and JS)

<! Doctyehtml>
<html>
<head>
  <style type="text/css">
    .div {
      color: blue
    }
  </style>
</head>
<body>
  <div class='div'> 
    Test dom load.
  </div>
  <script type="text/javascript">
    var a = 1 + 1;
  </script>
</body>
</html>
Copy the code

Here is just the difference from the above picture:

The first is a couple of jS-related items in yellow, one called Evaluate Script and the other, Compile Script.

The second difference is that layout is no longer done inside ParseHtml from the second readyStatechange event. Here I simply do a test, only CSS or JS exists, the same result is still the present, because CSS or JS block the entire page rendering process, because JS and CSS may set the style of the label, thus affecting the layout execution.

Test reflux and redraw

Timers are used next, because modern browsers are optimized for frequent reflow or redraw operations, which can be batched and have no effect.

backflow

When the size, structure, or attributes of some or all of the elements in the Render Tree change, the process by which the browser rerenders some or all of the document is called reflux.


<! Doctyehtml>
<html>
<head>
  <style type="text/css">
    .div {
      color: blue
    }
  </style>
</head>
<body>
  <div class='div'> 
    Test dom load.
  </div>
  <script type="text/javascript">
    var a = 1 + 1;
    document.getElementsByTagName('div') [0].style.marginTop = '20px'

    setTimeout(() = > {
      document.getElementsByTagName('div') [0].style.marginTop = '40px'
    }, 1000)
  </script>
</body>
</html>

Copy the code

redraw

When a change in the style of an element in a page does not affect its position in the document flow (e.g., color, background-color, visibility, etc.), the browser assigns the new style to the element and redraws it, a process called redraw.


<! Doctyehtml>
<html>
<head>
  <style type="text/css">
    .div {
      color: blue
    }
  </style>
</head>
<body>
  <div class='div'> 
    Test dom load.
  </div>
  <script type="text/javascript">
    var a = 1 + 1;
    document.getElementsByTagName('div') [0].style.color = 'green'

    setTimeout(() = > {
      document.getElementsByTagName('div') [0].style.color = 'red'
    }, 1000)
  </script>
</body>
</html>

Copy the code

conclusion

Update Layer Tree – “Paint -” Composite Layers Update Layer Tree – “Paint -” Composite Layers

Backflow causes redraw, redraw does not cause backflow.

An operation that causes backflow

Juejin. Cn/post / 684490… Operations that cause backflow:

  • Page first render
  • The browser window size changed. Procedure
  • The size or position of the element changed
  • Element content changes (number of words or image size, etc.)
  • Element font size changes
  • Add or remove visible DOM elements
  • Activate CSS pseudo-classes (such as: :hover)
  • Query some properties or call some methods

Some common properties and methods that cause backflow: ClientWidth, clientHeight, clientTop, clientLeft offsetWidth, offsetHeight, offsetTop, offsetLeft ScrollWidth, scrollHeight, scrollTop, scrollLeft scrollIntoView(), scrollIntoViewIfNeeded() getBoundingClientRect() scrollTo()

How to avoid

The following content source: juejin.cn/post/684490… 【 Nuggets – Waist 】

CSS

  • Avoid table layouts.
  • Change the class at the very end of the DOM tree whenever possible.
  • Avoid setting multiple inline styles.
  • Apply the animation to an element whose position attribute is absolute or fixed.
  • Avoid USING CSS expressions (such as calc()).

JavaScript

  • To avoid manipulating styles too often, it is best to override the style property once, or define the style list as class and change the class property once.
  • To avoid frequent DOM manipulation, create a documentFragment, apply all DOM manipulation to it, and finally add it to the document.
  • You can also set display: None to the element and display it after the operation is complete. Because DOM operations on elements with the display attribute none do not cause backflow and redraw.
  • Avoid frequently reading properties that cause backflow/redraw, and if you do need to use them more than once, cache them in a variable.
  • Use absolute positioning on elements with complex animations to keep them out of the document stream, which would otherwise cause frequent backflow of parent elements and subsequent elements.