There are many external resources that can be loaded on a page, such as scripts, styles, fonts, images and videos. How do these external resources affect the loading and rendering of the entire page? Today we’re going to find out.

After reading this article, you will have solved the following mystery:

  • How to customize web loading speed with Chrome?
  • Will images/videos/fonts block page loading?
  • How does CSS block page loading?
  • How does JS block page loading?
  • Does JS block DOM loading?
  • What are defer and async? And what are the characteristics?
  • Do dynamic scripts block?
  • How does blocking relate to DOMContentLoaded and onload?

Prepare the environment before the test

Before the test, we need to control the download speed of the browser and reset it to 50KB /s.

  1. Open theChromeDeveloper tools;
  2. inNetworkFind it under panelDisable cacheFrom the drop-down list on the right, select Add to Add custom throttling configuration.
  3. Add a 50KB /s download speed configuration;
  4. Finally, select the newly configured option from the drop-down list in the second step.
  5. Note: If the currently selected custom option is modified, you need to switch to another option and cut back for it to take effect.

Why this speed? Some of the following resources, such as images, styles, or scripts, are several times the size of 50KB, which is easy to test.

Pictures cause congestion

Write an example to see the result:

<! DOCTYPEhtml>
<html lang="en">
    <head>
        <meta charset="UTF-8"/>
        <script>
            document.addEventListener('DOMContentLoaded'.() = > {
                console.log('DOMContentLoaded')})window.onload = function() {
                console.log('onload')}</script>
    </head>
    <body>
        <h1>I'm an H1 tag</h1>
        <img src="https://xxx.oss-cn-shenzhen.aliyuncs.com/images/flow.png" />
        <h2>I'm an H2 tag</h2>
    </body>
</html>
Copy the code

The image above is about 200KB in size. When you set the Internet download speed to 50KB /s, you can open the page and see the following results: When the h1 and H2 tags are rendered and the DOMContentLoaded is printed, the image is still loading, which means that the image does not block the DOM loading, let alone the page rendering. When the image is loaded, the onLoad is printed, indicating that the image delays the onload event.

Videos, fonts, and images are essentially the same and do not block DOM loading and rendering.

CSS load blocking

Again, we’ll test the blocking effect of CSS loading directly in code, because the bootstrap. CSS loaded below is 192KB, so it should theoretically take about 3 to 4 seconds to download.

<! DOCTYPEhtml>
<html lang="en">
    <head>
        <meta charset="UTF-8"/>
        <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="stylesheet" />
    </head>
    <body>
        <h1>I'm an H1 tag</h1>
    </body>
</html>
Copy the code

The test process is as follows:

  1. inElementsUnder the panel, selecth1This label, and then pressdeleteKey from itDOMDelete, so as to simulate the first load;
  2. Refresh the browser, nowElementsIt’s loaded under the panelh1Tag, continue loading for 3 to 4 seconds (while loadingbootstrap.css), the page appearsI'm an H1 tagThe page has been rendered.

Thus draw the conclusion:

  • bootstrap.cssIt’s not loaded yet, andDOMIs already thereh1The label,instructionsCSSDoes not blockDOMThe resolution of;
  • Page untilbootstrap.cssIt doesn’t appear until the load is completeh1Copy in,instructionsCSSblocksDOMThe rendering of.

Why is that? Just think of the page rendering process. The browser first parses HTML to generate a DOM tree, then parses CSS to generate a CSSOM tree, and then synthesizes DOM tree and CSSOM tree to generate a rendering tree, through which the layout is carried out and the information of each node is calculated to draw the page.

It can be said that parsing DOM and CSS are actually parallel, since they are parallel, CSS and DOM do not affect each other, which is consistent with conclusion 1; In addition, the page must be rendered after the CSSOM tree is obtained, which is consistent with conclusion 2.

Does CSS block DOM rendering? The answer is no, when loading the outer chain style at the end of :

<body>
    <h1>I'm an H1 tag</h1>
    <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="stylesheet" />
</body>
Copy the code

When you refresh the browser, the page will immediately display the words “I am an H1 tag”. When the style load is completed 3 to 4 seconds later, the page will render the word again. This means that CSS blocks DOM rendering only the DOM defined behind the CSS. Secondary rendering can be a bad experience for the user and burdensome for the browser, so this is why it is necessary to load the outer chain styles early in the .

CSS blocks subsequent JS execution

CSS blocks subsequent DOM rendering, does it block JS execution?

<! DOCTYPEhtml>
<html lang="en">
    <head>
        <meta charset="UTF-8"/>
        <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="stylesheet" />
    </head>
    <body>
        <h1>I'm an H1 tag</h1>
        <script>
            console.log('888')
        </script>
    </body>
</html>
Copy the code

When refreshing the browser, you can see that there is no print under the browser Console, but 888 is printed when the style load is complete, indicating that CSS blocks the execution of the JS defined after it.

Why is that? Imagine if an operation performed in JS requires the style of the current H1 tag, and the desired result cannot be obtained because the style has not been loaded, thus proving that CSS needs to block the execution of the JS defined after it.

JS loading block

CSS blocks DOM rendering and JS execution defined after it. How does JS loading affect the rendering process?

<! DOCTYPEhtml>
<html lang="en">
    <head>
        <meta charset="UTF-8"/>
        <script src="https://cdn.bootcss.com/jquery/2.1.4/jquery.min.js"></script>
    </head>
    <body>
        <h1>I'm an H1 tag</h1>
    </body>
</html>
Copy the code

First remove the existing H1 tags (if any) from the page. Take a closer look at the Elements panel. When you refresh the browser, the H1 tag is not loaded (the screen stays blank) until JS is loaded and it appears in the DOM. This is enough to say that JS blocks the loading of the DOM defined after it, so you should load external JS at the end of to reduce the screen time of page loading.

Defer and async

Must JS block the loading of the DOM defined after it? Let’s test it out:

<! DOCTYPEhtml>
<html lang="en">
    <head>
        <meta charset="UTF-8"/>
        <script async src="https://cdn.bootcss.com/jquery/2.1.4/jquery.min.js"></script>
    </head>
    <body>
        <h1>I'm an H1 tag</h1>
    </body>
</html>
Copy the code

The result of the above test is that the h1 tag is displayed on the page, but the script has not finished loading. This indicates that the async script does not block DOM loading. We can test defer in the same way and get the same result.

We now know that when JS is loaded by defer or Async, it does not block DOM loading. So do you know what defer and async are? What’s the difference between the two?

Before answering these questions, let’s take a look at what happens when a browser parses HTML and encounters a script tag.

  • Suspend parsingDOM;
  • performscriptIn the script, if thescriptIs the external chain, it will download it first, download the completion of the execution immediately;
  • Continue parsing the remainder after executionDOM.

This is the case when parsing a normal external chain, normal external chain download and execution will block the page parsing; What if the external chain is loaded by defer or async?

deferThe characteristics of

  • fordeferscriptThe browser continues parsinghtml, and download scripts in parallel, etcDOMThe script doesn’t start executing until the build is complete, so it doesn’t block;
  • deferAfter the script is downloaded, the execution time must beDOMContentLoadedExecute before the event is emitted;
  • multipledeferScripts are executed in strict accordance with the order defined, rather than downloaded and executed first.

asyncThe characteristics of

  • forasyncscriptThe browser continues parsinghtmlAnd the script is downloaded in parallel. Once the script is downloaded, it will be executed immediately. anddeferAgain, it doesn’t block when it’s downloading, but if it’s finished downloadingDOMParsing is blocked while executing the script before parsing is complete.
  • asyncScript execution andDOMContentLoadedIt is not clear which comes first because the script may be inDOMIt may not be downloaded when the build is completed, or it may be already downloaded;
  • multipleasync, which is based on the principle of first download completion first, so they are especially prone to error when there is a sequential dependency between them.

Both defer and Async can only be used for external scripts, and they are ignored if the script does not have a SRC attribute.

Dynamic scripts cause blocking

In the case of the following code, when you refresh the browser, the page immediately shows me as an H1 tag, but it takes a few seconds to load the dynamically inserted script, so you can conclude that the dynamically inserted script does not block page parsing.

<! -- Omitted part of the content -->
<script>
    function loadScript(src) {
        let script = document.createElement('script')
        script.src = src
        document.body.append(script)
    }
    loadScript('https://cdn.bootcss.com/jquery/2.1.4/jquery.min.js')
</script>
<h1>I'm an H1 tag</h1>
Copy the code

Dynamically inserted scripts will be executed immediately after loading, which is consistent with async, so if you need to ensure the execution order of multiple inserted dynamic scripts, you can set script.async = false, and the dynamic scripts will be executed in the same order as deferred as they were inserted.

DOMContentLoaded and onload

Loading a resource in a browser involves two events, DOMContentLoaded and onload, so what’s the difference between them?

  • onload: When all resources on the page (includingCSS,JS, pictures, fonts, videos, etc.) are all loaded, and it is bound towindowOn the object;
  • DOMContentLoaded: When the HTML has been parsed and builtDOM, but external resources such as styles and scripts may not have finished loading, and the event needs to be bound todocumentOn the object;

You must have noticed that the style and script might not have been loaded when DOMContentLoaded was triggered.

DOMContentLoaded encountered script

When the browser processes an HTML document and encounters a

<script>
    document.addEventListener('DOMContentLoaded'.() = > {
    	console.log('DOMContentLoaded')})</script>
<h1>I'm an H1 tag</h1>
<script src="https://cdn.bootcss.com/jquery/2.1.4/jquery.min.js"></script>
Copy the code

DOMContentLoaded must be triggered after the script is executed. The answer is no, with two exceptions: async and dynamic scripts do not block DOMContentLoaded.

DOMContentLoaded encountered style

CSS does not block the parsing of the DOM, so DOMContentLoaded should not trigger until the external style is loaded.

<! DOCTYPEhtml>
<html lang="en">
    <head>
        <meta charset="UTF-8"/>
        <script>
            document.addEventListener('DOMContentLoaded'.() = > {
                console.log('DOMContentLoaded')})</script>
        <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="stylesheet"/>
    </head>
    <body>
        <h1>I'm an H1 tag</h1>
    </body>
</html>
Copy the code

Test result: DOMContentLoaded was printed before the style was loaded, which is consistent with our analysis. But must it be? DOMContentLoaded is not printed until the style has been loaded. If you add a

<! -- only part of the content is displayed.
<link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="stylesheet"/>
<script></script>
</head>
Copy the code

Refer to the article

  • DOMContentLoaded
  • Html.spec.whatwg.org/multipage/s…