The DOM tree

According to the W3C HTML DOM standard, all content in an HTML document is a Node (a total of 12 Node classes). The main nodes are as follows:

  • The entire document is a document node,
  • Each HTML element is an element node
  • The text inside an HTML element is a text node
  • Each HTML attribute is an attribute node
  • Comments are comment nodes

When the browser receives the HTML document from the server, it traverses the document nodes to generate a DOM tree. Parsing tree is a DOM tree, which is composed of DOM elements and attribute nodes. The root of the tree is the Document object

CCSOM rule tree

DOM and CSSOM are independent structures. CSSOM is a MAPPING of CSS styles on web pages that is similar to the DOM, but only for CSS, not HTML. CSSOM maps the rules in the stylesheet to the corresponding elements of the page.

HTML parse order:

Details vary from browser to browser, but in general:

  • Build top-down from HTML code

  • The download, parseHTML/parseCSS/executeJS, layout, paint in different threads. ParseHTML /parseCSS will be done in parallel, then layout will generate the render tree, and then paint will render. Executing JS brings you back to the Layout stage.

  • Script file loading/execution blocks subsequent DOM tree construction (javascript may alter the DOM tree)

    Improvements: In response to the above mentioned script blocking document parsing, major browsers such as Chrome and FireFox have some optimizations, such as opening another thread to parse the remaining document while executing the script to find and load other external resources (do not change the main thread DOM tree, only optimize the loading of external resources).

  • Encountering a CSS file blocks the build of the render tree, which means the DOM tree continues to build (because it is parallel and does not affect the DOM structure).

  • After downloading JavaScript, you can modify the DOM through the DOM API, and you can modify the Style scope Render Tree through the CSSOM API. Each change causes the Render Tree to be rearranged and redrawn.

Key render path

The key render path is the process by which the browser receives the requested HTML, CSS, javascript and other resources, parses, builds the tree, renders the layout, draws, and finally presents the interface to the customer.

So the browser rendering process mainly includes the following steps:

  1. Parsing the HTML generates a DOM tree.
  2. Parsing CSS generates a CSSOM rule tree.
  3. Combine the DOM tree with the CSSOM rule tree to generate the render tree.
  4. Traverse the render tree to start the layout, calculating the location size information for each node.
  5. Draws each node of the render tree to the screen.

Render block

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

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

CSS priority: CSS resources are introduced before JavaScript resources. 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.

Building a Render tree

From DOM trees and CSS rule trees we can build render trees. The browser iterates through each visible node starting at the root of the DOM tree. For each visible node, find the appropriate CSS style rule and apply it.

After the rendering tree is built, each node is visible and has its content and the style of the corresponding rule. This is the biggest difference between a render tree and a DOM tree. Render trees are used for display, so invisible elements are not present in the tree, for example. Otherwise, elements whose display equals none will not be displayed in the tree, but elements whose visibility equals hidden will be displayed in the tree.

Render tree layout

The layout phase starts at the root node of the render tree and determines the exact size and position of each node object on the page. The output of the layout phase is a box model that captures the exact position and size of each element on the screen.

Render tree rendering

In the paint phase, the render tree is traversed, calling the renderer’s paint() method to display its contents on the screen. The rendering tree is done by the browser’s UI back-end component.

Reflow and repaint:

Based on the render tree layout, compute CSS styles, which are geometric information such as the size and position of each node in the page. HTML has a streaming layout by default, and CSS and JS break this layout by changing the look and feel of the DOM as well as its size and position. Two important concepts come up here: replaint and reflow. Replaint: Part of the screen is redrawn without affecting the overall layout, e.g. the background color of a CSS is changed, but the geometry and position of elements remain the same. Reflow: means that the geometry of the component has changed and we need to revalidate and evaluate the render tree. Part or all of the render tree has changed. That’s a Reflow, or Layout. Reflow and Replaint should be kept to a minimum, which I think is one of the reasons why table layouts are rarely used today.

Display: None triggers reflow, visibility: The hidden property is not an invisible property, its semantics are to hide the element, but the element still occupies the layout space and will be rendered as an empty box, so visibility: Hidden will only trigger repaint because no position change has taken place.

In some cases, such as changing the style of an element, the browser does not reflow or repaint once immediately. Instead, the browser will accumulate a batch of such operations and do a reflow. This is also called asynchronous or incremental asynchronous reflow. In some cases, such as the resize window, the default font of the page is changed. For these operations, the browser reflow immediately.

Rearrange and redraw

When a web page is generated, it is rendered at least once. As the user visits, it is constantly re-rendered.

There are three things that can cause a page to be re-rendered.

  • Modify the DOM
  • Modify the style sheet
  • User events (such as mouse hovering, page scrolling, typing text in input fields, resize Windows, and so on)

To rerender, you need to regenerate the layout and redraw. The former is called “reflow” and the latter is “repaint”.

Note that “redraw” does not necessarily require “rearrangement”. For example, changing the color of a web element will only trigger “redraw”, not “rearrangement”, because the layout has not changed. However, reordering inevitably leads to redrawing. Changing the position of a web element, for example, triggers both reordering and redrawing because the layout has changed.

Impact on performance

It is inevitable that rearrangements and redraws will be triggered constantly. However, they are very resource-intensive and are the root cause of poor web page performance.

Improving web performance means reducing the frequency and cost of “rearranging” and “redrawing” and triggering re-rendering as little as possible.

As mentioned earlier, both DOM changes and style changes trigger rerendering. However, browsers have been smart enough to put all the changes together in a single queue and do it all at once, avoiding multiple rerenders.


div.style.color = 'blue';
div.style.marginTop = '30px';
Copy the code

In the code above, the div element has two style changes, but the browser only triggers a rearrangement and redraw.

If written badly, it triggers two rearrangements and redraws.


div.style.color = 'blue';
var margin = parseInt(div.style.marginTop);
div.style.marginTop = (margin + 10) + 'px';
Copy the code

After setting the background color for the div element, the second line asks the browser for the element’s location, so the browser has to rearrange it immediately.

In general, a style write followed by a read of any of the following attributes will cause the browser to immediately rerender.

  • offsetTop/offsetLeft/offsetWidth/offsetHeight
  • scrollTop/scrollLeft/scrollWidth/scrollHeight
  • clientTop/clientLeft/clientWidth/clientHeight
  • getComputedStyle()

So, for performance reasons, try not to put read and write operations in the same statement.


// bad
div.style.left = div.offsetLeft + 10 + "px";
div.style.top = div.offsetTop + 10 + "px";

// good
var left = div.offsetLeft;
var top  = div.offsetTop;
div.style.left = left + 10 + "px";
div.style.top = top + 10 + "px";
Copy the code

The general rule is:

  • The simpler the stylesheet, the faster the rearrangement and redrawing.
  • The higher the level of DOM elements rearranged and redrawn, the higher the cost.
  • Table elements cost more to rearrange and redraw than div elements

Nine tips for Improving performance

There are some tricks that can reduce the frequency and cost of browser rerenders.

The first, from the previous section, is that multiple reads (or writes) of the DOM should be placed together. Do not add a write operation between two read operations.

Second, if a style is rearranged, it is best to cache the results. Avoid rearranging your browser the next time you use it.

Third, do not change the style one by one, but change the style once by changing the class or csSText property.

// bad var left = 10; var top = 10; el.style.left = left + "px"; el.style.top = top + "px"; // good el.className += " theclassname"; // good el.style.cssText += "; left: " + left + "px; top: " + top + "px;" ;Copy the code

Fourth, try to use the offline DOM, rather than the real web DOM, to change element styles. For example, operate on a Document Fragment object and then add it to the DOM. Another example is the cloneNode() method, which operates on the cloned node and then replaces the original node with the cloned node.

Fifth, set the element to display: None (one rearrangement and redraw), perform 100 operations on this node, and finally restore the display (one rearrangement and redraw). That way, you have two re-renders instead of maybe 100.

Sixth, elements whose position attribute is absolute or fixed will have a relatively small cost of rearrangement, because there is no need to consider its influence on other elements.

Seventh, make the display attribute of an element visible only when necessary, because invisible elements do not affect rearrangement and redrawing. Additionally, the element visibility: hidden only affects redrawing, not rearrangement.

Eighth, use the virtual DOM script library, such as React etc.

Article 9, the use of the window. RequestAnimationFrame (), window. RequestIdleCallback () these two methods adjust to render after (see article).

Thought 1: Why is JavaScript at the bottom of an HTML document?

In general, browsers have two main features for running Javascript:

Execution immediately after loading blocks subsequent content of the page (including rendering of the page and downloading of other resources) cause: When referencing JS, the browser sends a JS request and waits for the return of the request. Because browsers need a stable DOM tree structure, javascript code that directly changes the DOM tree structure, such as document.write or appendChild, or even directly uses location.href, Browsers prevent JS from modifying the DOM tree and need to rebuild it, so they block other downloads and renderings.

Thus, if multiple JS files are introduced, these js files are loaded serially and executed sequentially for the browser. Because javascript may manipulate the DOM tree of HTML documents, browsers generally do not download JS files in parallel in the way CSS files are downloaded in parallel, because of the special nature of JS files. So, if your javascript wants to manipulate subsequent DOM elements, basically, the browser will report an error saying the object was not found. Because the following HTML is blocked while Javascript is executing, the DOM tree has no following DOM node. So the program reported an error. Basically, the script tag in the head blocks subsequent resource loads and entire page generation. If you put JavaScript at the top of the page, the DOM will not be parsed and rendered in the time it takes to download and parse JavaScript, and the browser will always be blank, so putting JavaScript files at the bottom of the page will help the page render quickly. So, you can see why a lot of websites put javascript at the end of their pages, or use events like window.onload or Docmuemt ready.

First, both async and defer are invalid for inline JavaScript

Defer: The script external link file set to defer will not block HTML parsing during the JS file download. Moreover, if the HTML has not been parsed when the JS download is complete, js will wait until the HTML document is parsed. If there are multiple JS downloads, they will be executed sequentially. That is, with defer, the loading of subsequent document elements will take place in parallel (asynchronously) with the loading of script.js, but the execution of script.js will be completed after all elements have been parsed and before the DOMContentLoaded event is fired. Async: a script linked file with async set does not block HTML parsing during js downloading, but executes immediately after js downloading, regardless of whether the HTML is being parsed or not. That is, with async, the loading and rendering of subsequent document elements will take place in parallel with the loading and execution of script.js (asynchronously). To summarize, defer is “render before execution” and Async is “download after execution”.

Thought 2: Why should Css be included in the tags of HTML documents

If a CSS file reference is placed at the bottom of an HTML document, the browser will prevent unstyled content from flickering by not displaying anything until the CSS file has been downloaded and parsed, resulting in a white screen. (When tested in Firefox, however, styles flicker, which is a tradeoff between different browsers: display the CSS after it has been fully parsed, or display it first and then redraw the style after it has been parsed.) When a CSS file is placed in head, CSS parsing also blocks subsequent DOM rendering, But parsing CSS is also parsing THE DOM, so once the CSS is parsed, the page will be rendered step by step.

Simple process: Web pages run in a variety of browsers, and the speed at which the browser loads and renders the page directly affects the user experience. To put it simply, page rendering is the process by which the browser displays THE HTML code in the browser window according to the rules defined by CSS. Here’s an overview of how browsers work:

1. The user enters the URL (suppose it is an HTML page and it is accessed for the first time). The browser sends a request to the server, and the server returns an HTML file. 2. The browser starts loading the HTML code and finds a tag inside the tag that references an external CSS file. 3. The browser sends a CSS file request, and the server returns the CSS file. 4. The browser continues to load part of the HTML code, and the CSS file is in hand, ready to start rendering the page 5. The browser finds a tag in the code that references an image and sends a request to the server. Instead of waiting for the image to download, the browser continues to render the code that follows; 6. The server returns the image file, because the image occupies a certain area, affecting the layout of the following paragraphs, so the browser needs to go back and re-render this part of the code; 8. The Javascript script executes this statement, which tells the browser to hide one of the lines in the code

(style. The display = “none”). Unfortunately, the element was suddenly missing and the browser had to re-render the code; 9. When it finally arrived, the browser burst into tears… 10. Wait, the user clicks the “skin” button in the interface, and Javascript tells the browser to change the CSS path of the tag. 11. Browser called the group together and said, “Pack your bags, everybody. We have to start over…” The browser asks the server for a new CSS file and rerenders the page.

Javascript code runs in two stages:

1. Pre-parsing phase

All function definitions are brought forward, all variable declarations are brought forward, and variable assignments are not brought forward. (Preprocessing skips execution statements and processes only declarations, again from top to bottom. All declarations, including variables and functions, are processed first before any code is executed. Even if the declaration is made below the call, the browser still declares and then invokes (executes), a phenomenon called “promotion.” So, even if a function is declared at the bottom, the function can still be executed at the front. Assignments or other logical operations are performed during the execution phase and are ignored during the preprocessing phase.

2. Execution phase – Execution from top to bottom (according to the JS runtime mechanism)

Summary Whether inline or outlink JS will block subsequent DOM parsing and rendering for an HTML document, whether inline or outlink CSS, will block subsequent DOM rendering, but will not block subsequent DOM parsing.

How to speed up the LOADING of HTML pages

1. Page weight loss a. Page weight is the most important factor affecting the speed of loading. B. Delete unnecessary Spaces and comments. C. Move inline script and CSS to an external file. D. You can use HTML Tidy to slim down HTML, and you can use some compression tools to slim down JavaScript.

2. Reduce the number of files: a. Reduce the number of files referenced on the page to reduce the number of HTTP connections. B. Many JavaScript and CSS files can be merged.

3. Reduce domain name search: a. DNS search and resolution of domain names is also time-consuming, so reduce references to external JavaScript, CSS, images and other resources, and use different domain names as little as possible.

4. Cache reused data: a. Cache reused data.

5. Optimize the loading order of page elements: a. First load the content initially displayed on the page and related JavaScript and CSS, and then load htML-related things, like what is not initially displayed related to the image, flash, video and other very fat resources loaded last.

6. Reduce the amount of Inline JavaScript: a. The browser Parser assumes that inline JavaScript changes the page structure, so using inline JavaScript is expensive. B. Instead of using document.write() for output, use modern W3C DOM methods for processing page content for modern browsers. \

7. Use modern CSS and legal tags: a. Use modern CSS to reduce tags and images, for example, using modern CSS+ text can completely replace some images only with text. \ 8.b. Use valid tags to avoid “error correction” and other operations by browsers when parsing HTML, and HTML Tidy can be used to reduce HTML weight.

8.Chunk your content: a. Instead of using nested tables, use non-nested tables or div. Break a layout based on a large nested table into smaller tables so that you don’t have to wait until the entire page (or large table) is loaded.

9. Specify the size of the image and table: a. If the browser can immediately determine the size of the image or table, it can immediately display the page without having to rearrange the layout. B. This not only speeds up the page display, but also prevents improper layout changes after the page has finished loading. C. Image uses height and width.

Performance analysis

Chrome Performance page Performance Analysis Guide

The Performance is introduced

First, open the webpage in the new traceless window, open Chrome DevTools and switch to Performance, you can see the following screen

Buttons in areas 1 and 3 in the figure above can be used to trigger performance data recording, black buttons can record performance data in the interaction phase, and round arrow buttons can record performance data in the loading phase. The area in figure 2 can set the network loading speed and CPU speed of the current page.

Now click on the black button to generate a performance report for the interaction phase

Part ONE: Overview

Here is the main interface of whole rendering, each time period to perform the sequence of events, from above we can know that we each time period (down to ms) did that, when the mouse on it, we also can be in the form of a larger version to check our rendering situation of interface of each time period, the Performance will be a few key indicators, Things like page frame rate (FPS), CPU resource consumption, network request traffic, V8 memory usage (heap memory), etc., are graphed in chronological order.

Part II:The performance of the panel

The performance panel mainly consists of the following parts. 1.Net Work We can intuitively see the sequence and duration of resource loading. 2. Timings are used to record the data information generated at some key time points, such as FP, FCP, LCP, etc. 4.Main is an important part of Performance tool, which records the execution records of the Main thread in the rendering process. Click main to see the details of a task’s execution. 5.Com Positor Compositing thread execution log, used to record the layer compositing operation after the HTML Paint phase. 7.GPU The execution process of the main thread of the GPU process is recorded. For example, you can intuitively see when GPU acceleration is enabled. The Memory option, when checked, displays a line chart that shows how we performed at different times. We can see the memory usage of the page, such as JS Heap, if the curve keeps growing, then there is a memory leak. If the memory curve does not fall for a long time, there is the possibility of a memory leak. By analyzing each part of the performance panel and locating problems, you can have a deeper understanding of how the browser works

Part 3: Summary (Performance Summary)

It’s a way of counting what was done in the time frame we used to check performance: Loading time, Scripting js computing Rendering time, Painting time Other times, Idle time of the browser

The Performance practice

Here is an example to illustrate the use of the performance panel, click on the automatic restart page in the traceless window, and record the whole page loading process, and then analyze the results ~

Network &&hang

Performance panel, there are many, many parameters, and we’re going to look at some of the more common ones. First take a look at the white screen time and network loading, as shown in figure \

Above, we can look at some information: The white during the time of the page load is about 150 ms load resources from the network, image is not enabled http2, so every time the number of images can be loaded at the same time is limited, has not been loaded pictures are waiting for loading time can also see process resources In addition, we can have a look at the resource loading have a blank period, although the above no. However, if there is a blank period between resource loading, it indicates that the idle time of resource loading is not fully utilized. You can adjust it.

Flame figure

The flame chart, mainly in the Main panel, is the panel we look at most when analyzing specific functions. Let’s take a look, as shown in the figure below:

First of all, there are many tasks in the panel. If the Task takes a long time, it will be marked in red on the upper right corner. In this case, we can select the Task marked in red and zoom in to see its specific time. So if YOU zoom in, you can see what you’re doing, what functions are taking how much time, and you can see the compressed code, and you can see the compressed function name. Then we click on a function, and at the bottom of the panel, we get information about the code, which function it is, how long it takes, what line it is in which file, etc. This makes it easy to locate the time consuming function. At the same time, we can also check the Main index to analyze whether there are forced synchronous layout and other operations in the code. After analyzing these reasons, we can optimize our program targeted

Timeline && memory condition

In the Timings section, we can see some key times of this loading, respectively:

FCP: First Contentful Paint LCP: Largest Contentful Paint FMP: First Meaningful Paint DCL: DOMContentLoaded Event L: We can select Onload Event (select the area from the white screen to the area with content, which represents the page loading process of this time). We can compare the above time, as shown in the screenshot below:

  • Blue: Network communication and HTML parsing
  • Yellow: JavaScript execution
  • Purple: Style calculation and layout, i.e., rearrangement
  • Green: Redraw

Loading events

The event describe
Parse HTML The browser performs HTML parsing
Finish Loading Network request completion event
Receive Data The response data of the request arrives at the event, which may be triggered multiple times if the response data is large (unpacked)
Receive Response Triggered when the response header packet arrives
Send Request Triggered when a network request is sent

Scripting event

The event describe
Animation Frame Fired Triggered when a defined animation frame occurs and the callback processing begins
Cancel Animation Frame Triggered when canceling an animation frame
GC Event Triggered when garbage is collected
DOMContentLoaded Triggered when the DOM content in the page has been loaded and parsed
Evaluate Script A script was evaluated.
Event Js event
Function Call Triggered only when the browser enters the JS engine
Install Timer Triggered when a timer is created (calling setTimeout() and setInterval())
Request Animation Frame A requestAnimationFrame() call scheduled a new frame
Remove Timer Triggered when a timer is cleared
Time Triggered by a call to console.time()
Time End Triggered by a call to console.timeend ()
Timer Fired The timer is triggered after the callback is activated
XHR Ready State Change Triggered when an asynchronous request becomes ready
XHR Load Triggered when an asynchronous request has finished loading

Rendering events

The event describe
Invalidate layout Triggered when a DOM change invalidates the page layout
Layout Triggered when page layout calculations are executed
Recalculate style Triggered when Chrome recalculates element styles
Scroll Triggered when the embedded window scrolls

Painting event

The event describe
Composite Layers Chrome’s rendering engine is triggered when the image layer is merged
Image Decode Trigger when an image resource completes decoding
Image Resize Trigger when an image is resized
Paint Triggered when the merged layer is drawn to the corresponding display area

In addition, we can see the memory usage in the page, such as JS Heap, if the curve keeps growing, then there is a memory leak. Note That repeated addition of Nodes and Listeners may occur.

The bottom is time-consuming profile of a whole page, if Scripting time is too long, then js execution logic is too much, can consider to optimize the js, if the rendering time is too long, consider optimizing rendering process, if too much free time, can consider to make full use of it, such as the free time to elevate the some operations on the page report, etc.