Defer and async features are believed to be "familiar and unfamiliar" to many JavaScript developers, with two features that, literally, are well understood, respectively, as "deferred scripts" and "Asynchronous scripts". However, in the case of defer, some of the details may not be familiar to developers, such as: when the script with the defer feature is delayed until when it is executed, and whether the internal and external scripts can support the Defer;defer script in addition to delaying execution, what are the special places and so on. This paper combines some existing articles and the two features in the MDN document, and makes a more comprehensive study and summary of defer and async, hoping to help developers better grasp these two features.
1 Introduction
In the code execution sequence of JavaScript script loading and execution in browser environment, we mentioned that the execution of JavaScript code blocks the parsing rendering of the page and downloads of other resources, of course because JavaScript is a single-threaded language, which means that under normal circumstances, JavaScript code in a page can only be executed sequentially from top to bottom, and of course, as we analyzed in the sequence of code execution for JavaScript script loading and execution in browser environments, For example, by document.write into a script or introducing a script via dynamic scripting, the sequence of JavaScript code execution is not necessarily strictly in order from top to bottom, and defer and async are what we call "abnormal situations".
We often say that JavaScript execution is blocking, and in actual development, the blocking that we usually care about the most, and the blocking that most affects the user experience, should be the following:
[1] Blocking of page parsing and rendering
[2] We write page initialization scripts (typically listening to the script that the Domcontentloaded event is bound to, which is the script we want to execute first, because we'll write the code that is most relevant to user interaction here)
[3] Blocked page external resource downloads (e.g. pictures)
If we had a time-consuming scripting operation, and the script blocked the three places we mentioned above, the performance or user experience of the Web page would be very poor.
Defer and Async are also intended to address or mitigate the impact of blocking on the page experience, and we'll look at these two features, and we'll look at these two features in a holistic way:
[1] When is the execution time of a deferred or asynchronous script? What about the blocking of the page?
[2] are both internal and external scripts able to implement latency or asynchrony?
[3] What is the browser's support for these two features? Are there any related bugs?
[4] What else do you need to be aware of when using scripts that use these two features?
2 Defer characteristics
2.1 About the timing of the execution of defer scripts
The defer feature is the extended feature defined in the HTML4 specification, initially supported only by ie4+ and firefox3.5+, and then browsers such as Chrome have added support for defer= "defer". Defer means delay, which is delaying the execution of the script. Normally, the script we introduce will be downloaded and executed immediately, and after the defer feature, the script will not execute immediately after downloading, but wait until the page is resolved. Let's take a look at the HTML4 Standard's description of defer:
Defer:when Set, this boolean provides a hint to the "user agent" that's not going to generate any docu ment content (e.g., no "document.write" in JavaScript) and thus, the user agent can continue parsing and rendering.
That is, if you set up defer, then tell the user agent that the script does not produce any document content so that the user agent can continue parsing and rendering. Let's take a look at the key descriptions of defer in MDN:
Defer:if The async is not present but the defer attribute is present, then the script are executed when the page has finished parsing.
Through the definitions in the standard, we can be clear that: defer script will not block the parsing of the page, but wait until the end of the page parsing, but the time-consuming defer can still block the download of external resources, then it will block the domcontentloaded event? In fact, the defer script is still executed before the domcontentloaded event, so it still blocks the script in domcontentloaded. We can help understand the timing of the defer script by following the diagram:
According to the standard definition, internal scripts do not support defer, while IE9 and the following browsers provide defer support for internal scripting.
Browser support for 2.2 defer
Now let's take a look at the browser support for the defer feature:
IE9 and the following browsers have a bug that will be described in detail later in the demo.
Functional verification of 2.3 demo:defer characteristics
We imitated the function of defer features in the way that Olivier Rochard used in the script defer:
First we prepared 6 external scripts:
1.js:
Test = "I am head external script \ n";
2.js
Test + = "I am the body external script \ n";
3.js
Test + = "I am the bottom external script \ n";
Defer1.js
Test + = "I am the head external delay script \ n";
Defer2.js
Test + = "I am the body external delay script \ n";
Defer3.js
Test + = "I am the bottom external delay script \ n";
The code in HTML is:
Code, in order to facilitate the implementation of the Domcontentloaded event, we introduced jquery (the following article will also explain how to implement a compatible domcontentloaded), and then we in the head of the script, The body inside and outside the body to introduce delay scripts and normal script, and through a global string to record the execution of each piece of code, we look at the results of the implementation of each browser:
IE7 |
IE9 |
IE10 |
Chrome |
Firefox |
I'm head of the external script I'm the head internal script. I am the body external script I'm the bottom of the external script I'm head. External delay script I'm head delay internal script I'm the body. External delay Script I'm the bottom external delay script I'm a domcontentloaded inside the script. I'm a window.onload inside the script. |
I'm head of the external script I'm the head internal script. I am the body external script I'm the bottom of the external script I'm head. External delay script I'm head delay internal script I'm the body. External delay Script I'm the bottom external delay script I'm a domcontentloaded inside the script. I'm a window.onload inside the script. |
I'm head of the external script I'm head delay internal script I'm the head internal script. I am the body external script I'm the bottom of the external script I'm head. External delay script I'm the body. External delay Script I'm the bottom external delay script I'm a domcontentloaded inside the script. I'm a window.onload inside the script. |
I'm head of the external script I'm head delay internal script I'm the head internal script. I am the body external script I'm the bottom of the external script I'm head. External delay script I'm the body. External delay Script I'm the bottom external delay script I'm a domcontentloaded inside the script. I'm a window.onload inside the script. |
I'm head external script I'm head
delay Internal script I'm head internal script I'm body external script I'm the bottom external script I'm head
external delay script
I am the body external delay script I'm the
bottom external delay script
I'm domcontentloaded inside the script
I'm window.onload inside the script
|
From the results of the output, we can determine that only IE9 and the following browsers support the internal latency script, and that the defer script will be triggered before the domcontentloaded event, so it can also jam the domcontentloaded event.
Defer feature bugs for 2.4 demo:ie<=9
From the demo in section 2.3, you can see that the defer scripts can still be executed in the order they were added. In ie<=9, this problem has a bug: if we add more than one defer script to the document, and there are appendchild,innerhtml,insertbefore in the previous script, ReplaceChild and so on modifies the DOM's interface invocation, the subsequent script may be preceded by the script execution. You can refer to GitHub's ISSUE:HTTPS://GITHUB.COM/H5BP/LAZYWEB-REQUESTS/ISSUES/42
We verify by demo that the 1.js code is first modified (this code is only for simulation, in fact, this code has a great performance problem):
Document.body.innerHTML = "<div id= ' div ' > I was later joined by </div>";
Document.body.innerHTML + = "<div id= ' div ' > I was later joined by </div>";
Document.body.innerHTML + = "<div id= ' div ' > I was later joined by </div>";
Document.body.innerHTML + = "<div id= ' div ' > I was later joined by </div>";
Document.body.innerHTML + = "<div id= ' div ' > I was later joined by </div>";
Document.body.innerHTML + = "<div id= ' div ' > I was later joined by </div>";
Document.body.innerHTML + = "<div id= ' div ' > I was later joined by </div>";
Alert ("I am the 1th script");
2.js
Alert ("I am the 2nd script");
To modify the code in HMTL:
Normally, the order of the pop-up box in the browser must be: I am the 1th script-"I am the 2nd script, but in ie<=9, the execution result is: I am the 2nd script-" I am the 1th script, verifying the bug.
Summary of 2.5 defer
Before summing up, the first point to note: As mentioned in the standard, defer scripts should not appear document.write operations, the browser will directly ignore these operations.
In general, the role of defer is somewhat similar to placing the script at the bottom of the page, but because of bugs in ie<=9, if multiple defer are present on the page, the sequence of scripts may be disrupted so that code dependencies can go awry. As a result, the defer attribute is rarely used in the actual project, and the script code placed at the bottom of the page replaces the functionality provided by defer.
3 Async characteristics
3.1 about the timing of the execution of async scripts
Async features are introduced in the HTML5, using the following method: async= "Async", we first look at the standard for the async characteristics of the relevant description:
Async:if The async is present, then the script'll be executed asynchronously, as soon as it is available.
It needs to be pointed out that here the asynchronous, refers to the asynchronous loading rather than asynchronous execution, that is, the browser encountered a async script tag, will be asynchronous to load (personally think that the process is mainly the process of downloading), once loaded will execute the code, and the process of execution is certainly synchronized, which is blocked. We can get a comprehensive understanding of defer and async by following the diagram:
In this way, the timing of the execution of the async script is uncertain, because it is also indeterminate when the script is loaded. Let's use the demo below to get a feel for:
Async1.js
Alert ("I am an asynchronous script");
HTML code:
Here we borrowed "JavaScript script loading and execution in browser environment code execution sequence" the Delayfile foot in the script provides a delay, in the browser that supports async, the order of the balloons is generally: I am the synchronized script--"I am the asynchronous script."
Browser support for 3.2 async
Now let's take a look at the browser support for the async feature:
As you can see, only ie10+ supports async features, Opera Mini does not support async features, and Async does not support internal scripting.
Summary of 3.3 Async
Async refers to an asynchronous script, that is, the script is loaded asynchronously, the loading process does not cause blocking, but the timing of the execution of the async script is indeterminate and the order of execution is uncertain, so the script using async should be a script that does not rely on any code (such as Third-party statistics or ad code), Failure to do so will result in an error in execution.
4 priority issues for defer and async
This is better understood, and the standard stipulates:
[1] If the <script> element defines both defer and async attributes, press Async to handle it (note: The async feature is ignored directly for browsers that do not support async)
[2] If the <script> element defines only defer, it is handled in a deferred script
[3] If the <script> element is not defined defer also does not define async, then the normal situation, namely: the script immediately loaded and executed