Preface
The rendering principle of browser is a required course for every front-end development engineer, and there are many articles on the network, but most just tell you that browser behaves like this, and there is no intuitive understanding, which makes people forget instantly after reading.
So Xiaobian decided to simulate some scenes in browser rendering through node practice, to verify some viewpoints of articles on the market, in order to deepen their understanding.
Before you start, learn some basic knowledge about the rendering mechanism of your browser, as shown in the following figure:
DOM: Document Object Model, a browser that parses HTML into a tree-shaped data structure, referred to as DOM.
CSSOM:CSS Object Model, browser parses CSS code into tree data structure
Render Tree: A merge of DOM and CSOM results in a Render Tree(Render Tree, like DOM, stores the css properties of each node, the properties of the node itself, and the child nodes of the node as a multifork tree)
Node Instance Derivation
To facilitate the observation of static resource loading and rendering details, build a static server using node with the following code:
const http = require('http'); const fs = require('fs'); let hostname = '127.0.0.1'; let port = 8080; let server = http.createServer((req, res) => { console.log(req.url); if (req.url == '/a.js') { fs.readFile('src/a.js', (err, data) => { res.writeHead(200, {'Content-Type': 'text/javascript'}); setTimeout(() => { res.write(data); res.end(); }, 10000) // Delay 10s to return a.js file }) } else if(req.url == '/b.js') { fs.readFile('src/b.js', (err, data) => { res.writeHead(200, {'Content-Type': 'text/javascript'}); res.write(data); res.end(); }) } else if(req.url == '/index.html') { fs.readFile('src/index.html', (err, data) => { res.writeHead(200, {'Content-Type': 'text/html'}); res.write(data); res.end(); }) } else if (req.url == '/style.css') { fs.readFile('src/style.css', (err, data) => { res.writeHead(200, {'Content-Type': 'text/css'}); res.write(data); res.end(); }) } }) server.listen(port, hostname, () => { console.log(`server has already started: ${hostname}:${port}`) })
From the code above, we know that a.js's request is delayed by 10 seconds to respond to the return
Start the server and open http://127.0.0.1:8080/index.html in the browser
1. Validation Question 1: How are external static resources requested?
index.html file content
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Browser Rendering Principle</title> <script src='http://127.0.0.1:8080/a.js'></script> <link rel="stylesheet" href="http://127.0.0.1:8080/style.css"> </head> <body> <p id='hh'>1111111</p> <script src='http://127.0.0.1:8080/b.js'></script> <p>222222</p> <p>3333333</p> </body> </html>
Refresh the page and look at Timeline, as shown in the following image:
From the above animation, we can get the following points:
- Page is not displayed until 10s, so a.js blocks the rendering of the page;
- The first Parse HTML parsing was blocked by a.js, and the pre-parsing initiated a request for style.css, b.js, so the three static resources seem to be requesting together, which requires a look at the later validation;
- All three static resources make requests when resolving html tags, which need to be verified again.
Modify the html content below
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Browser Rendering Principle</title> <link rel="stylesheet" href="http://127.0.0.1:8080/style.css"> </head> <body> <p id='hh'>1111111</p> <p>repeat</p> <p>repeat</p> .... ....Repeat 5000 lines <script src='http://127.0.0.1:8080/a.js'></script> <script src='http://127.0.0.1:8080/b.js'></script> <p>222222</p> <p>3333333</p> </body> </html>
Refresh the page and you get the following TimeLine picture:
From the picture we can see:
- When there is too much html content, browsers need to receive it in segments and parse it in segments.
- Static resources are not requested at the same time, nor are they requested only when the specified label is resolved. The browser will decide for itself that if the current operation is time consuming, it will request the following resources, so the timing of static resource requests cannot be determined. The browser has multiple compatible processing schemes.
2. Validation Question 2: The impact of JS on HTML parsing and rendering
// index.html file <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Browser Rendering Principle</title> <link rel="stylesheet" href="http://127.0.0.1:8080/style.css"> </head> <body> <p id='hh'>1111111</p> <script src='http://127.0.0.1:8080/b.js'></script> <script src='http://127.0.0.1:8080/a.js'></script> <p>222222</p> <p>3333333</p> </body> </html>
Refresh the page and execute as shown in the following animation:
From the execution we found that due to a.js'delayed return, A.js was not downloaded and the Dom tree parsing build process was blocked, but the html tags parsed before A.js were rendered.When A.js download is complete, continue parsing the following tags and rendering the display.Of course, the browser does not parse a label to draw the display once, but only when it encounters blocking or time-consuming operations.
To summarize, JS can block page parsing and rendering, which is why JS files are often placed at the bottom of pages
3. Validation Question 3: The Impact of CSS on Page Rendering Resolution
Modify the server node code to delay style.css for 10 seconds before returning
// style.css p:nth-child(1) { color: red; } p:nth-child(2) { color: blue; } p:nth-child(3) { color: green; }
// index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Browser Rendering Principle</title> <link rel="stylesheet" href="http://127.0.0.1:8080/style.css"> </head> <body> <p id='hh'>1111111</p> <p>222222</p> <p>3333333</p> </body> </html>
Refresh the page and execute as shown in the following animation:
From the above execution process, it was found that style.css returned after a delay of 10 seconds, and the page dom tree was parsed and constructed normally, but not rendered.When the CSS download is complete, the page is rendered and the style takes effect.
Modify the location of style.css in index.html to the bottom of the body with the following code:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Browser Rendering Principle</title> </head> <body> <p id='hh'>1111111</p> <p>222222</p> <p>3333333</p> <link rel="stylesheet" href="http://127.0.0.1:8080/style.css"> </body> </html>
Refresh the page and execute as shown in the following animation:
As you can see from the animation, the delayed loading of style.css does not block the parsing build and rendering of the previous dom tree, and the rendered P element does not have a style.When the style.css download is complete, the element's style takes effect and displays.
To sum up, CSS does not block the building parsing of a dom tree, only the rendering of the elements behind it, not the elements before it.
If the CSS is placed at the bottom of the page, the Unstyled page content will be rendered first, and when the CSS loading style takes effect, the page will look shaky, so CSS is usually placed in the head.
4. Effect of Pictures on Page Rendering and Resolution
Modify the node code to delay code.png as follows:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Browser Rendering Principle</title> <link rel="stylesheet" href="http://127.0.0.1:8080/style.css"> </head> <body> <p id='hh'>1111111</p> <img src="./code.png"/> <p>222222</p> <p>3333333</p> </body> </html>
Refresh the page and execute as shown in the following animation:
As you can see from the animation, pictures do not block resolution or rendering.
summary
Based on the above examples, we draw the following important conclusions:
- Static resources are not requested at the same time or only when they are resolved to a specified tag, and the browser will decide for itself.
- JS will block the parsing and rendering of the page, while the browser also has pre-parsing, encountered a blocking can continue to parse the following elements;
- CSS`does not block the build resolution of the dom tree, only the rendering of the elements behind it, not the rendering of the elements before it;
- Pictures do not block resolution or rendering.
Browsers, like black boxes, can learn about browser rendering from both the source code of the browser and the debugging tools provided by the browser. Some articles on the web summarize best practices, which will be more impressive.
Reference resources
https://segmentfault.com/a/1190000007766425
Sweep the public number that pays attention to me, and more wonderful content will accompany you!