We all know that the application layer of the World Wide Web uses THE HTTP protocol and uses a browser as an entry point to access resources on the web. When accessing a website using a browser, users need to send HTTP requests to the server. The server then returns HTML files and response information. At this point, the browser parses and renders the HTML file (which also includes requesting non-inline CSS and JavaScript files or other resources from the server), and finally renders the page to the user.
Now that we know that rendering a web page is done by the browser, if a site’s page loads too slowly, it can lead to an unfriendly user experience. This article introduces some basic browser performance optimizations by going through the process of rendering a web page. Improve the user experience by allowing the browser to render your web pages faster and respond quickly.
SylvanasSun([email protected]) Reprint, please be sure to put the following paragraph in the article beginning (keep hyperlinks). This article first from SylvanasSun Blog, the original link: SylvanasSun. Making. IO / 2017/10/03 /…
Key render path
The browser received the return from the serverHTML
,CSS
andJavaScript
The rendering process by which bytes of data are parsed and converted into pixels is called the critical rendering path. By optimizing key render paths, you can shorten the browser rendering time.
The browser needs to build the DOM and CSSOM trees before rendering the page (without the DOM and CSSOM trees there is no way to determine the structure and style of the page, so they must be built first).
DOM tree is called Document Object Model. It is a programming interface for HTML and XML documents and provides a structured representation of documents. It defines a way for programs to access the structure (for example, JavaScript uses the DOM to manipulate structure, style, and content). The DOM parses a document into a collection of nodes and objects, so a WEB page is essentially a DOM.
Cascading Style Sheets Object Model (CSS) The CSSOM tree is called the Cascading Style Sheets Object Model (CSS). It is not that different from a DOM tree, except that it is a collection of CSS objects.
Construct DOM tree and CSSOM tree
After the browser gets the HTML bytes from the network or disk, it goes through a process to parse the bytes into a DOM tree:
-
Encoding: The raw bytes of HTML data are first converted to the characters specified in the file encoding.
-
Tokenization: The browser then converts the string into tokens according to the HTML specification (tags such as < HTML >, , strings and attributes in tags are converted into tokens, each with a special meaning and a set of rules). Tokens record the beginning and end of tags. This feature makes it easy to determine whether a tag is a child tag (assuming that there are two tags, < HTML > and , when the < HTML > tag token encounters the tag token before it encounters its closing token
). Then is a child tag of < HTML >. -
Generate objects: Each token is then transformed into an object (the node object) that defines its properties and rules.
-
Completion: The DOM tree is completed, and the entire collection of objects looks like a tree structure. One might wonder why the DOM is a tree structure, because there are complex parent-child relationships between tags, and the tree structure explains this relationship (CSSOS, cascading styles also have parent-child relationships). For example, div p {font-size: 18px} will look for all p tags and determine whether the parent tag is div before deciding whether to render in this style.
The entire DOM tree building process is essentially byte -> character -> token -> node object -> object model, which is illustrated more visually with a sample HTML code and illustration below.
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet">
<title>Critical Path</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg"></div>
</body>
</html>Copy the code
When the HTML code above encounters a tag, the browser will send a request for the CSS file of the tag. (Using inline CSS can skip the request step for speed, but there is no need to lose modularity and maintainability for this speed.) style.css reads as follows:
body { font-size: 16px }
p { font-weight: bold }
span { color: red }
p span { display: none }
img { float: right }Copy the code
Once the browser gets the data from the external CSS file, it starts building the CSSOM tree just as it would a DOM tree, and the process is no different.
If you want more detail to experience the key rendering path construction, can use the Timeline in the Chrome developer tools function, it records the browser resources from the request page to render various operating process, even can record the process of a certain period of time (not recommended to see too much of a web site, information will be mixed and disorderly).
Building a Render tree
After building the DOM tree and the CSSOM tree, the browser simply has two separate object sets. The DOM tree describes the structure and content of the document, and the CSSOM tree describes the style rules applied to the document. To render a page, you need to combine the DOM tree with the CSSOM tree, which is called the render tree.
-
The browser will traverse every visible node starting at the root of the DOM tree. (Invisible nodes do not need to be rendered to the page. Invisible nodes also include nodes whose display: None property is used by CSS. The hidden property is not an invisible property, its semantics are to hide the element, but the element still occupies layout space, so it is rendered as an empty box.
-
For each visible node, find the appropriate CSS style rule and apply it.
-
Once the render tree is built, each node is visible and contains its content and the style of the corresponding rule.
After the rendering tree is built, the browser has the content and style of each visible node, and the next step is to calculate the exact position and size of each node in the window, which is the layout phase.
CSS uses a mental model called the box model to represent the distance between each node and other elements. The box model includes Margin, Padding, Border, and Content. Each TAB on a page is actually a box.
Layout phase can be started from the root node of the render tree traversal, each node is determined and then the exact size and the location of the object on the page, the output of the layout phase is a box model, it can accurately capture the exact location and size of each element in the screen, all relative measurements can also be converted to absolute pixel values in the screen.
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Critial Path: Hello world!</title>
</head>
<body>
<div style="width: 50%">
<div style="width: 50%">Hello world!</div>
</div>
</body>
</html>Copy the code
When the Layout event is complete, the browser immediately issues Paint Setup and Paint events to start rendering the tree into pixels. The time required to render is proportional to the complexity of the CSS style. Once the rendering is complete, the user can see the final rendering of the page.
It may only take a second or two to send a request to a web page and get the rendered page, but the browser has already done a lot of the work described above. To summarize the entire process of the browser’s key render path:
-
Process HTML tag data and generate a DOM tree.
-
Process CSS markup data and generate CSSOM trees.
-
Merge the DOM tree with the CSSOM tree to generate the render tree.
-
Traverse the render tree to start the layout, calculating the location of each node.
-
Draw each node to the screen.
Optimization of rendering blocking
Browsers need to build DOM and CSSOM trees to render a page, and if HTML and CSS file structures are large and complex, this can have a serious impact on page loading speed.
The so-called rendering blocking resource means that the request for the resource needs to be made before the corresponding DOM tree or CSSOM tree is built. This behavior obviously delays the start time of the rendering operation. HTML, CSS, and JavaScript are all resources that block rendering. HTML is required (rendering is impossible without DOM), but you can also optimize CSS and JavaScript to minimize blocking.
Optimizing CSS
If CSS resources can be used only under certain conditions, they can be loaded for the first time without building the CSSOM tree, and only when certain conditions are met will the browser block rendering and build the CSSOM tree.
This is what CSS media queries do, consisting of media types and zero or more expressions that check the health of a particular media feature.
<! -- Without media query, this CSS resource will block rendering -->
<link href="style.css" rel="stylesheet">
<! -- All is the default type, which has the same effect as unset media query -->
<link href="style.css" rel="stylesheet" media="all">
<! Dynamic media queries, which will be calculated when the web page loads. Portrait. CSS may or may not block rendering, depending on the direction of the device when the page loads. -->
<link href="portrait.css" rel="stylesheet" media="orientation:portrait">
<! It is only applied when printing a web page, so it does not block rendering when the web page is first loaded in the browser. -->
<link href="print.css" rel="stylesheet" media="print">Copy the code
Using media queries can makeCSS
Resources don’t block rendering on the first load, but either wayCSS
Resources their download requests will not be ignored, and browsers will still download CSS files first
Optimization of JavaScript
When the browser’s HTML parser encounters a script tag, it pauses building the DOM and then passes control to the JavaScript engine, which starts executing the JavaScript script until the browser picks up where it left off and continues building the DOM. 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. Obviously, if you don’t use JavaScript in the right place, it can seriously affect rendering speed.
The JavaScript script in the following code does not work because the JavaScript script starts executing before the DOM tree is built to the
tag. This is why it is common to write inline JavaScript code at the bottom of HTML files, or to use window.onload() and $(function(){}) in JQuery (there are some differences between these two functions, Window.onload () is an event that fires when the page is fully loaded, and $(function(){}) is executed when the DOM tree is built.
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet">
<title>Hello,World</title>
<script type="text/javascript">
var p = document.getElementsByTagName('p') [0];
p.textContent = 'SylvanasSun';
</script>
</head>
<body>
<p>Hello,World!</p>
</body>
</html>Copy the code
Async tells the browser that the script doesn’t need to be executed at the reference location, so the browser can continue building the DOM and the JavaScript script will start executing when it’s ready. This will significantly improve the performance of the first page load (async can only be used within SRC tags, which are externally referenced JavaScript files).
<! -- The following two uses are equivalent -->
<script type="text/javascript" src="demo_async.js" async="async"></script>
<script type="text/javascript" src="demo_async.js" async></script>Copy the code
Optimized summary of key render paths
Now that we’ve covered how the browser renders the page and how to prepare for it, we’ll summarize how to optimize key render paths with the following examples.
Suppose you have an HTML page that introduces only one CSS external file:
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet">
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg"></div>
</body>
</html>Copy the code
Its key render paths are as follows:
First of all, the browser should first send a request to the server to obtain the HTML file, and then start to build the DOM tree. When the tag is met, the browser needs to send a request to the server again to obtain the CSS file, and then continue to build the DOM tree and the CSSOM tree. The browser merges the rendering tree and calculates the layout according to the rendering tree. Perform the draw operation and the page is rendered.
There are several terms used to describe key render path performance:
-
Key resources: Resources that may block the first rendering of a page (two in the image above, the HTML file and the external CSS file style.css).
-
Critical path length: the number of round trips or total time required to obtain critical resources (in the figure above, two or more times are required to obtain HTML files and CSS files at one time. This number is based on the maximum TCP congestion window. A file may not be transferred within one connection).
-
Key byte: the sum of file sizes of all key resources (figure 9KB).
Next, the requirements for the case code change and it adds a JavaScript file.
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet">
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg"></div>
<script src="app.js"></script>
</body>
</html>Copy the code
JavaScript files block the DOM tree construction and wait for the CSSOM tree to be built before executing the JavaScript script. The key render path features in the figure above are as follows:
-
Key Resources: 3 (HTML, style.css, app.js)
-
Critical path length: 2 or more (the browser downloads style.css and app.js together in one connection)
-
Key bytes: 11KB
Now, we’ll optimize the key render path by first adding async to the
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet">
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg"></div>
<script src="app.js" async></script>
</body>
</html>Copy the code
-
Key resources: 2 (app.js is loaded asynchronously and will not block rendering resources)
-
The critical path length is 2 or greater
-
Key bytes: 9KB (app.js is no longer a key resource, so its size is not counted)
Next, optimize CSS, such as adding media queries.
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet" media="print">
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg"></div>
<script src="app.js" async></script>
</body>
</html>Copy the code
-
Key resources: 1 (App.js is loaded asynchronously, style.css is only used for printing, so HTML is the only key resource left, that is, when the DOM tree is built, the browser will start rendering)
-
The critical path length is 1 or greater
-
Key bytes: 5KB
Optimizing key render paths is optimizing key resources, key path length, and key bytes. The less critical resources there are, the less preparation the browser has to do before rendering; Similarly, critical path length and key bytes are related to the efficiency with which the browser downloads resources; the fewer they are, the faster the browser downloads resources.
Other optimization schemes
In addition to asynchronous loading of JavaScript and using media queries there are many other optimizations to make the first load of a page faster. These can be used in combination, but the core idea is to optimize for critical rendering paths.
Load part of HTML
When a server receives a request, it responds with only the initial portion of the HTML, with subsequent HTML content retrieved via AJAX when needed. Since the server only sends part of the HTML file, it takes a lot less work to build the DOM tree, which makes the page feel fast to the user.
Note that this approach does not work with CSS, and browsers do not allow CSSOM to build only the initial part, otherwise the specific style will not be determined.
The compression
The compression of external resources can greatly reduce the amount of resources that the browser needs to download, reduce the critical path length and key bytes, and make the page load faster.
To compress the data is to reencode the data with fewer bits. There are a lot of compression algorithms out there, and each of them has a different function area, and their complexity is different, but I won’t talk about the details of the compression algorithm here, interested friends can Google.
Before you can compress files like HTML, CSS, and JavaScript, you need to do a redundant compression. Redundant compression is the removal of redundant characters, such as comments, Spaces, and newlines. These characters are useful to programmers, since unformatted code is horrible to read, but they don’t make any sense to browsers, and removing redundancy can reduce the amount of data in a file. After redundant compression, the data itself is further compressed using a compression algorithm, such as GZIP (GZIP is a generic compression algorithm that works with any byte stream and remembers what it has seen before, and then tries to find and replace the duplicate content). .
HTTP cache
Retrieving resources over the network is usually slow and requires multiple round trips between the browser and the server to obtain the complete resource file if it becomes too large. The cache can reuse previously acquired resources, and since the backend can use the cache to reduce the overhead of accessing the database, the front-end can also use the cache to reuse resource files.
Browsers come with HTTP caching, just make sure that the header of each server response contains the following attributes:
-
ETag: ETag is a delivery validation token that checks for updates to a resource and does not transmit any data if the resource has not changed. When the browser sends a request, it sends the ETag along with it to the server, which checks the token against the current resource (ETag is usually a fingerprint that has been hashed). If the resource has Not changed, the server returns a 304 Not Modified response, so the browser doesn’t have to download the resource again. Instead, we continue to reuse the cache.
-
Cache-control: Cache-control defines the Cache policy, which specifies under what conditions responses can be cached and for how long.
-
No-cache: No-cache indicates that you must confirm with the server whether the returned response has changed, and then use the response to satisfy subsequent requests to the same URL. (Each request is sent to the server based on the ETag to confirm the change. If the change does not occur, the browser will not download the resource.)
-
No-store: no-store directly disallows the browser and all intermediate caches to store any version of the response. In simple terms, this policy disallows any caching and downloads the server’s response in its entirety each time a request is sent.
-
Public&private: If the response is marked public, the browser can cache the response even if it has associated HTTP authentication and even if the response status code is not normally cacheable. If the response is marked private, the response is usually cached only for a single user and therefore is not allowed to be cached by any intermediate CDN. Private is typically used to cache user private information pages.
-
Max-age: specifies the maximum cache duration, in seconds, starting from the request time.
-
Resource preloading
Pre-fetching
Is a way to prompt the browser to pre-load resources that the user may use later.
Use dns-prefetch to do DNS resolution ahead of time so that you can quickly access another host name later (the browser will cache the resolution of the domain name in the web page when loading, so that you do not need to do additional DNS resolution for later visits, reducing user wait time and improving page load speed).
<link rel="dns-prefetch" href="other.hostname.com">Copy the code
The prefetch property is used to pre-download resources, although it has the lowest priority.
<link rel="prefetch" href="/some_other_resource.jpeg">Copy the code
Chrome allows you to use the subresource attribute to specify the highest priority download resource (prefetch will be downloaded only after all subresource resources have been downloaded).
<link rel="subresource" href="/some_other_resource.js">Copy the code
Prerender is a prerender page that is pre-rendered and hidden, and then opens to skip the rendering phase and is displayed directly to the user (pre-rendered pages that the user must visit next are recommended, otherwise it is not worth the cost).
<link rel="prerender" href="//domain.com/next_page.html">Copy the code
reference
-
Web Fundamentals | Google Developers
-
Flushing the Document Early | High Performance Web Sites
-
Introduction to the DOM – Web APIs | MDN
-
How the Browser Pre-loader Makes Pages Load Faster – Andy Davies