Have been doing front-end for several years, recently want to enter a big factory, participated in the interview of Ali, Baidu, toutiao, was completely hit, feel their foundation is not very strong, so the germination of the idea of heavy preschool end, to accustomed knowledge/skills, ask a why, know more about the principle, or source code

Today we are going to talk about the order in which resources are loaded and executed in HTML.

I’ve been working on the front end for a few years, but can you answer the question of how to load the execution file when the browser gets the HTML file

  • In what order are files loaded?
  • How many files can be loaded at a time?
  • Will JS be executed before the CSS is loaded?
  • What is the difference between Async and defer?
  • DOMContentLoaded event and onLoad event, when to trigger?

To find out, let’s do an experiment, and I’m using Chrome.

HTML to load the order and number of resources

We will construct an HTML file and load 10 CSS files and 10 JS files alternately in the head. The addresses of these files are created using the local PHP service. The data will be delayed for 3 seconds so that we can see the effect clearly


      
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="http://test.com/test/css1">
    <script src="http://test.com/test/js1"></script>
    <link rel="stylesheet" href="http://test.com/test/css2">
    <script src="http://test.com/test/js2"></script>
    <link rel="stylesheet" href="http://test.com/test/css3">
    <script src="http://test.com/test/js3"></script>
    <link rel="stylesheet" href="http://test.com/test/css4">
    <script src="http://test.com/test/js4"></script>
    <link rel="stylesheet" href="http://test.com/test/css5">
    <script src="http://test.com/test/js5"></script>
    <link rel="stylesheet" href="http://test.com/test/css6">
    <script src="http://test.com/test/js6"></script>
    <link rel="stylesheet" href="http://test.com/test/css7">
    <script src="http://test.com/test/js7"></script>
    <link rel="stylesheet" href="http://test.com/test/css8">
    <script src="http://test.com/test/js8"></script>
    <link rel="stylesheet" href="http://test.com/test/css9">
    <script src="http://test.com/test/js9"></script>
    <link rel="stylesheet" href="http://test.com/test/css10">
    <script src="http://test.com/test/js10"></script>
</head>
<body>
</body>
</html>
Copy the code

The CSS and JS addresses are constructed using the PHP framework. The purpose is to use PHP’s sleep delay return resource to give us a clearer view of the timing. You can construct them yourself using Node or any other backend

    //js file, wait for 3s to return
    public function actionJs1(a){
        sleep(3);
        return "console.log('js1111111')";
    }
    // CSS file, wait for 3s return
     public function actionCss1(a){
        sleep(3);
    }
Copy the code

The browser first downloads HTML files, then requests CSS1, js1, CSS2, JS2, CSS3, and jS3 in document order. You can see that the browser can load 6 files at a time, and then load another 6 files until all files are loaded.

And the loading sequence is actually tested several times, all are [CSS1, JS1, CSS2, JS2, CSS3, JS3], [CSS4, CSS5, CSS6, CSS7, CSS8, CSS9], [CSS10, JS4, JS5, JS6, JS7, JS8], [JS9, JS10], As you can see, there are two features: overall, documents are loaded in the order they appear in HTML, but CSS files are partially loaded first

To prove this, the HTML code has been modified to put all 10 CSS in front and all 10 JS in back

    <link rel="stylesheet" href="http://test.com/test/css1">.<link rel="stylesheet" href="http://test.com/test/css10">
    <script src="http://test.com/test/js1"></script>.<script src="http://test.com/test/js10"></script>
Copy the code

Sure enough, the browser loads the first 10 CSS first before loading js

What if we put 10 JS files in front of 10 CSS files

    <script src="http://test.com/test/js1"></script>.<script src="http://test.com/test/js10"></script>
     <link rel="stylesheet" href="http://test.com/test/css1">.<link rel="stylesheet" href="http://test.com/test/css10">
Copy the code

As you can see, the browser loads 6 JS, then 10 CSS first before loading js

Next, add 10 images to the body, and check the loading order of CSS, JS, and image. Without testing, we should also think that the image should come after CSS and JS.

Construct test HTML, set 6 per resource, in the following order

    <link rel="stylesheet" href="http://test.com/test/css1">.<link rel="stylesheet" href="http://test.com/test/css6">
    
    <img src="http://test.com/test/img1"/>.<img src="http://test.com/test/img6"/>
     <script src="http://test.com/test/js1"></script>.<script src="http://test.com/test/js6"></script>

Copy the code

Chrome files load six CSS files, six JS files, and six images

The browser can only load 6 files at a time, so can you load more? What happens if you load different resource domains?

// The first six CSS domains are test.com<link rel="stylesheet" href="http://test.com/test/css1">.<link rel="stylesheet" href="http://test.com/test/css6">// The last six CSS domains are m.test.com<link rel="stylesheet" href="http://m.test.com/test/css1">.<link rel="stylesheet" href="http://m.test.com/test/css6">

Copy the code

As you can see, the browser loads 12 files at once

conclusion

1. The browser loads files in the order in which they appear in HTML

2. But CSS will be loaded first, then JS, and finally images

3. Google Browser loads six resources of the same domain name at a time. Resources of different domain names can be loaded in parallel

This should give us some ideas for performance optimization, such as using different domain names to improve overall loading speed

Timing of JS execution in HTML

Is js executed immediately after loading, or is it affected by other factors? If CSS is delayed by 3s and JS is cancelled and returns immediately, see what happens

// The CSS delays returning data by 3s<link rel="stylesheet" href="http://test.com/test/css1">//js returns immediately, console.log('js1')<script src="http://test.com/test/js1"></script>
Copy the code

If you refresh the page, you can see that the JS is loaded quickly, but it is not executed immediately. It takes about 3s for the js to be executed, that is, after the CSS is loaded, the loading of the CSS will block the execution of JS. Is that because the CSS is in front of the JS?

If we switch the order of CSS and JS, we can see that the JS prints immediately and does not wait for the CSS to load

//js returns immediately, console.log('js1')<script src="http://test.com/test/js1"></script>// The CSS delays returning data by 3s<link rel="stylesheet" href="http://test.com/test/css1">
Copy the code

conclusion

  1. If the CSS is in front of the JS, the loading of the CSS will block the execution of the JS, that is, the execution of the JS after the LOADING of the CSS
  2. If CSS comes after JS, js execution is not blocked

Let’s take a look at the loading order of the two js, starting with the most common one

//js1 delay returns data for 5s, console.log('js1')<script src="http://test.com/test/js1"></script>//js2 delay 3s return data, console.log('js2')<script src="http://test.com/test/js2"></script>
<script>
    console.log('js3')
</script>
Copy the code

After 5s, the console prints jS1, jS2 and jS3 successively. Although JS2 is loaded in advance, it still needs to wait for the completion of jS1 loading before it can be executed

There are two asynchronous loading methods for JS async and defer. Next, let’s add async properties to JS

//js1 delay returns data for 5s, console.log('js1')<script src="http://test.com/test/js1" async></script>//js2 delay 3s return data, console.log('js2')<script src="http://test.com/test/js2" async></script>
<script>
    console.log('js3')
</script>
Copy the code

The console immediately prints in order

js3
js2
js1
Copy the code

As you can see, adding the async attribute JS does not block the execution of the js that follows it, and the defer attribute will be added as the loading completes first.

//js1 delay returns data for 5s, console.log('js1')<script src="http://test.com/test/js1" defer></script>//js2 delay 3s return data, console.log('js2')<script src="http://test.com/test/js2" defer></script>
<script>
    console.log('js3')
</script>
Copy the code

The console prints in the following order. As you can see, the JS that added the defer attribute does not block subsequent JS execution, but the JJS that added the defer attribute are still executed in the same order.

js3
js1
js2
Copy the code

Below is a comparison diagram of classical JS loading execution time.

  • Browsers will immediately load and execute js that do not have asynchronous attributes added, which blocks HTML parsing

  • The browser will load js with async property immediately (of course, if Google Browser does not add async, it will recognize THE JS file in HTML in advance for loading, as discussed in the first part) and execute js immediately after loading. Js with multiple async properties will be executed first if they are loaded first

  • The js that the browser encounters with the defer attribute will be loaded immediately, but not executed immediately. Instead, it will be executed after the HTML parsing is complete and before DOMContentLoaded fires. Js with multiple defer attributes are executed in document order

As mentioned above, the JS that added the defer attribute will execute after the document has been parsed and before DOMContentLoaded is triggered, meaning that the DOM will be available in the JS that added the defer attribute

//js1 delays 5s to return data, console.log(document.getelementbyid ('test'))<script src="http://test.com/test/js1" defer></script>
 <script>
    console.log(document.getElementById('test'))
</script>

<div id="test"></div>
Copy the code

Inline js, before the DOM with ID = “test”, so output null, while the JS of the defer attribute prints out the DOM

null
<div id="test"></div>
Copy the code

In the JS of the defer property, you can safely manipulate the DOM

conclusion

  1. If the CSS is in front of the JS, the loading of the CSS will block the execution of the JS, that is, the execution of the JS after the LOADING of the CSS
  2. If CSS comes after JS, js execution is not blocked
  3. Non-asynchronous JS executes sequentially
  4. Js with multiple async properties that are loaded first and executed
  5. The JS for the defer property executes after the document is parsed and before DOMContentLoaded is triggered, and the JJS for the multiple defer properties execute in document order

DOMContentLoaded and onload

Check some information on the Internet, the general saying is like this

When the onLoad event is triggered, all the DOM, style sheets, scripts, images, and Flash on the page have been loaded.

2. When the DOMContentLoaded event is triggered, only when the DOM is loaded, excluding stylesheets, images, and Flash.

But this is not the case through testing, assuming CSS returns delayed by 3s and images return delayed by 5s, let’s look at printing

// The CSS delays returning data by 3s<link rel="stylesheet" href="http://test.com/test/css1">
<script>
    document.addEventListener('DOMContentLoaded'.function () {
        console.log('DOMContentLoaded')},false)

    window.onload=function () {
        console.log("onload")}</script>// Delay the return of data for 5s<img src="http://3w.com/test/img1"/>
Copy the code

We can see that DOMContentLoaded will be printed after 3s and onload will be printed after 5s. That is to say, DOMContentLoaded needs to wait for the CSS to complete loading. As we said earlier, the JS of the defer attribute will be executed before DOMContentLoaded. What if the defer attribute returns 3s late? Let’s see what happens

<script>
    document.addEventListener('DOMContentLoaded'.function () {
        console.log('DOMContentLoaded')},false)

    window.onload=function () {
        console.log("onload")}</script>// Js1 delays the return of 3s data<script src="http://test.com/test/js1" defer></script>// Delay the return of data for 5s<img src="http://3w.com/test/img1"/>
Copy the code

Similarly, DOMContentLoaded is printed after 3s and onload is printed after 5s. It can be said that the conclusion on the Internet is inconsistent with the reality

conclusion

  1. Onload is triggered when all the DOM, style sheets, scripts, images, and Flash on the page have been loaded.
  2. DOMContentLoaded is triggered when DOM load parsing is complete, CSS load is complete, inline JS execution is complete, and js of the defer attribute is complete. Images and ASYNc js will not prevent DOMContentLoaded from being loaded.

The same conclusions also provide some ideas for front-end optimization, such as adding async properties to JS, reducing the size of JS and CSS, using lazy loading to reduce image requests and make them enter onload events as soon as possible, etc

Interested students welcome to pay attention to the public account, let’s re-learn the front end together, consolidate the foundation.