Hello, dear gentlemen. You’ve probably heard that putting CSS at the head and JS at the bottom can improve the performance of the page. But why? Have you thought about it? For a long period of time, I know it but I do not know why, forced back down to deal with the assessment of course, but the practical application is inevitable in a complete mess. Therefore, wang, Yang, Bu, mian, and I will summarize the recent achievements.

Friendly tips, this article is also small white to the main, if you want to see the conclusion can be pulled to the bottom of the ~


Since it is related to file reading, it definitely needs a server, I will put all the files on Github, give me a star, I will be happy! A “like” on nuggets would make me even happier

The only thing to explain on the Node side is this function:

function sleep(time) { return new Promise(function(res) { setTimeout(() => { res() }, time); })}Copy the code

Well! It’s actually delayed. If the CSS or JS file name has a prefix such as sleep3000, this means that the file will be returned with a delay of 3000 milliseconds.

The HTML file used below looks like this:

<! DOCTYPE html> <html lang="en">
    <head>
    	<meta charset="UTF-8">
    	<title>Title</title>
    	<style>
    		div {
    			width: 100px;
    			height: 100px;
    			background: lightgreen;
    		}
    	</style>
    </head>
    <body>
    	<div></div>
    </body>
    </html>
Copy the code

I’m going to insert different JS and CSS into it.

Common.css, with or without a prefix, looks like this:

div {
  background: lightblue;
}
Copy the code

Well, the words are not the majority, start the text!

CSS

As far as CSS is concerned, everyone knows that

CSSDoes not blockDOMThe resolution of

Pay attention to oh!

const div = document.querySelector('div');
console.log(div);
Copy the code

The DEFER property, as I’m sure you’ll be familiar with, is described by MDN to notify the browser that the script will execute after the document is parsed and before the DOMContentLoaded event is triggered. Setting this property ensures that the DIV will be printed as soon as the DOM parses.

It takes about 3s to render a light blue div. This proves that CSS does not block parsing of the DOM. Even though the CSS takes 3s to download, the browser will parse the DOM instead of waiting for the CSS to download.

Here briefly, the browser is parsing the DOM to generate THE DOM Tree, combined with CSS generated CSS Tree, finally composed of render Tree, and then render the page. The CSS cannot affect the DOM Tree during this process and therefore does not block DOM parsing. However, if the DOM Tree and CSS Tree are combined into a render Tree, will CSS block the render?

CSSBlock page rendering

If CSS does not block the page, the browser will render a light green div before the CSS file is downloaded, and then a light blue div. This is actually a smart strategy for the browser. Imagine if it weren’t for this strategy, the page would appear to be the same as it was before the CSS was downloaded and then suddenly look different. The user experience is terrible, and rendering costs money.

Therefore, for performance and user experience reasons, the browser will render as little as possible, and CSS will naturally block the rendering of the page.

However, things are always weird. In this example, the HTML header structure looks like this:

<header>
    <link rel="stylesheet" href="/css/sleep3000-common.css">
    <script src="/js/logDiv.js"></script>
</header>
Copy the code

But let’s think about where this leads.

The answer is that the browser will spin around for three seconds without printing anything, then render a light blue div and print null. It looks like CSS is blocking not only page rendering, but DOM parsing as well. Wait a minute, before you start flipping the table and making fun of me, please think about what is blocking DOM parsing. We just proved that CSS does not block, so it is JS blocking page parsing! But obviously the JS code is so simple, certainly will not block so long, that is JS waiting for CSS to download, why?

When you think about it, this actually makes sense, because if the content of the script is to get the style of the element, the width and height of the CSS controlled properties, the browser needs to compute that, which is CSS dependent. The browser has no idea what the script content is, so to avoid style fetching, it has to wait until all the previous styles have been downloaded before executing JS. Hence the situation in the previous example.

So, do you understand why

JS

The

JSblockingDOMparsing

First we need a new JS file named blok.js with the following content:

const arr = [];
for (let i = 0; i < 10000000; i++) {
  arr.push(i);
  arr.splice(i % 3, i % 7, i % 5);
}
const div = document.querySelector('div');
console.log(div);
Copy the code

In fact, the array operation is meaningless, just to make the JS file take longer to execute. And then I insert this file into the header, and the browser runs.

The result, as you can imagine, is that the browser circles around for a while, and nothing happens. Then it prints null, and a light green div appears. This is enough to show that JS blocks DOM parsing. The browser doesn’t know what the script is about. If it parses the following DOM first, the browser will be doing nothing if it deletes the rest of the DOM from the script. Not to mention the insane document.write. The browser can’t predict what’s inside, so it just stops and waits for the script to execute.

The optimization of this is also very obvious, which falls into two categories. If the JS file is too large and you’re sure it’s not necessary to block DOM parsing, add either defer or async property as needed, and the script will not block DOM parsing during the download.

If the file takes too long to execute, you can split the code. If you don’t need to execute the code immediately, you can use the old dirty technique: setTimeout(). Of course, modern browsers are smart enough to “peek” at the rest of the DOM, and when we come across tags like ,

Browser encounter<script>Tag will trigger page rendering

This detail may not be clear to many readers, but it is the reason why the JS execution above waits for the CSS to download. In the example above, the structure of the body in HTML is as follows:

<body>
	<div></div>
	<script src="/js/sleep3000-logDiv.js"></script>
	<style>
		div {
			background: lightgrey;
		}
	</style>
	<script src="/js/sleep5000-logDiv.js"></script>
	<link rel="stylesheet" href="/css/common.css">
</body>
Copy the code

This is an extreme example, but it tells us something important. Imagine what the page would look like.

The answer is light green, then light gray, and finally light blue. As you can see, the browser renders the page every time a

summary

From what has been discussed above, we come to the conclusion that:

  • CSSDoes not blockDOMBut will blockDOMRendering.
  • JSblockingDOMParse, but the browser peeks.DOM, download relevant resources in advance.
  • Browser encounter<script>And there is nodeferorasyncProperty will trigger page rendering, so if the precedingCSSThe browser waits until the resource is loaded before executing the script.

So, do you see why

Thank you for seeing here, I hope this article is helpful to you, there are different or better opinions of the big guy, also hope not hesitate to give advice! Thank you ~