Home >Web Front-end >JS Tutorial >Analysis of JavaScript script loading and execution in browser environment: defer and async characteristics_javascript skills
The defer and async features are believed to be two features that many JavaScript developers are "familiar but not familiar with". From a literal point of view, the functions of the two are easy to understand. They are "delay script" and "asynchronous script" respectively. effect. However, taking defer as an example, developers may not necessarily be familiar with some details, such as: when will a script with the defer feature be delayed to be executed; whether both internal scripts and external scripts can support defer; scripts after defer In addition to delayed execution, what are the special features, etc. This article combines some existing articles and the description of the two features in MDN documents to conduct a more comprehensive study and summary of defer and async, hoping to help developers better master these two features.
1 Introduction
In "Analysis of JavaScript Script Loading and Execution in the Browser Environment: Code Execution Sequence" we mentioned that the execution of JavaScript code will block the parsing and rendering of the page and the downloading of other resources. Of course, due to JavaScript is a single-threaded language, which means that under normal circumstances, the JavaScript code in a page can only be executed in order from top to bottom. Of course, as in " Analysis of JavaScript Script Loading and Execution in the Browser Environment As we analyzed in "Execution Sequence ", in some cases, such as when entering a script through document.write or introducing a script through dynamic script technology, the execution order of JavaScript code does not necessarily follow the strict order from top to bottom. defer and async are also what we call "abnormal situations".
We often say that the execution of JavaScript is blocking. In actual development, the blocking that we are usually most concerned about and the blocking that affects the user experience the most should be the following aspects:
[1] Blocking of page parsing and rendering
[2] The page initialization script we wrote (generally the script bound to listen to the DOMContentLoaded event). This part of the script is the script we want to execute first, because we will write the code most relevant to user interaction here. )
[3] Blocking of downloading external resources on the page (such as pictures)
If we have a time-consuming script operation, and this script blocks the three places we mentioned above, then the performance or user experience of this web page will be very poor.
The original intention of the two features of defer and async is also to solve or alleviate the impact of blocking on the page experience. Let’s analyze these two features below. We mainly understand these two from the following aspects. Features:
[1]When is the execution time of delayed or asynchronous scripts? What about page blocking?
[2] Are both internal and external scripts capable of delay or asynchronous implementation?
[3]How well does the browser support these two features? Are there any related bugs?
[4] Is there anything else that needs to be paid attention to when using scripts that use these two features?
2 defer feature
2.1 About the execution timing of defer script
The defer feature is an extended feature defined in the HTML4 specification. Initially, it was only supported by IE4 and Firefox3.5. Later, browsers such as Chrome also added support for it, using defer="defer". defer means delay, which means it will delay the execution of the script. Under normal circumstances, the script we introduce will be downloaded and executed immediately. However, with the defer feature, the script will not be executed immediately after downloading, but will be executed after the page is parsed. Let’s take a look at the HTML4 standard’s explanation of defer:
defer: When set, this boolean attribute provides a hint to the user agent that the script is not going to generate any document content (e.g., no "document.write" in javascript) and thus, the user agent can continue parsing and rendering.
In other words, if defer is set, it tells the user agent that this script will not produce any document content, so that the user agent can continue to parse and render. Let’s take another look at the key description of defer in MDN:
defer: If the async attribute is not present but the defer attribute is present, then the script is executed when the page has finished parsing.
Through the definition in the standard, we can make it clear that the defer script will not block the parsing of the page, but will wait until the page parsing is completed before executing it. However, the time-consuming defer may still block the download of external resources, then Will it block the DOMContentLoaded event? In fact, the defer script is still executed before the DOMContentLoaded event, so it will still block the script in DOMContentLoaded. We can use the following figure to help understand the execution timing of the defer script:
According to the definition in the standard, internal scripts do not support defer, but browsers IE9 and below provide defer support for internal scripts.
2.2 defer browser support
Let’s take a look at browser support for the defer feature:
There is a bug in IE9 and below browsers, which will be explained in detail in the DEMO later.
2.3 DEMO: Function verification of defer feature
We imitate the method used by Olivier Rochard in "the script defer attribute" to verify the function of the defer attribute:
First we prepared 6 external scripts:
1.js:
test = "I am head external script n";
2.js
test = "I am a body external script n";
3.js
test = "I am the bottom external script n";
defer1.js
test = "I am head external delay script n";
defer2.js
test = "I am body external delay script n";
defer3.js
test = "I am the bottom external delay script n";
The code in HTML is:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> <title>defer attribute test</title> <script src="http://lib.sinaapp.com/js/jquery/1.9.1/jquery-1.9.1.min.js"></script> <script type="text/javascript">var test = "";</script> <script src="defer1.js" type="text/javascript" defer="defer"></script> <script src="1.js" type="text/javascript"></script> <script defer="defer"> test += "我是head延迟内部脚本\n"; </script> <script> test += "我是head内部脚本\n"; </script> </head> <body> <button id="test">点击一下</button> <script src="defer2.js" type="text/javascript" defer="defer"></script> <script src="2.js" type="text/javascript"></script> </body> <script src="defer3.js" type="text/javascript" defer="defer"></script> <script src="3.js" type="text/javascript"></script> <script> $(function(){ test += "我是DOMContentLoaded里面的脚本 "; }) window.onload = function(){ test += "我是window.onload里面的脚本 "; var button = document.getElementById("test"); button.onclick = function(){ alert(test); } } </script> </html>
In the code, in order to facilitate the implementation of the DOMContentLoaded event, we introduced jQuery (later articles will introduce how to implement compatible DOMContentLoaded yourself). Then, we introduced delay scripts in the head, inside the body and outside the body of the script. and normal scripts, and records the execution status of each piece of code through a global string. Let’s take a look at the execution results in each browser:
IE7 | IE9 | IE10 | CHROME | firefox | ||||||||||
|
I am head external script I am head internal script I am a body external script I am the bottom external script I am head external delay script I am head delay internal script I am a body external delay script I am the bottom external delay script I am the script in DOMContentLoaded I am the script in window.onload | I am head external script I am head delayed internal script I am head internal script I am a body external script I am the bottom external script I am head external delay script I am a body external delay script I am the bottom external delay script I am the script in DOMContentLoaded I am the script in window.onload | I am head external script I am head delayed internal script I am head internal script I am a body external script I am the bottom external script I am head external delay script I am a body external delay script I am the bottom external delay script I am the script in DOMContentLoaded I am the script in window.onload |
从输出的结果中我们可以确定,只有IE9及以下浏览器支持内部延迟脚本,并且defer后的脚本都会在DOMContentLoaded事件之前触发,因此也是会堵塞DOMContentLoaded事件的。
2.4 DEMO:IE0f630a08ba48c70580451c5807d38ff4我是后来加入的16b28748ea4df4d9c2150843fecfba68";
document.body.innerHTML += "7a6bc4f2a125532aca32e87dac970576我是后来加入的16b28748ea4df4d9c2150843fecfba68";
document.body.innerHTML += "7a6bc4f2a125532aca32e87dac970576我是后来加入的16b28748ea4df4d9c2150843fecfba68";
document.body.innerHTML += "7a6bc4f2a125532aca32e87dac970576我是后来加入的16b28748ea4df4d9c2150843fecfba68";
document.body.innerHTML += "7a6bc4f2a125532aca32e87dac970576我是后来加入的16b28748ea4df4d9c2150843fecfba68";
document.body.innerHTML += "7a6bc4f2a125532aca32e87dac970576我是后来加入的16b28748ea4df4d9c2150843fecfba68";
document.body.innerHTML += "7a6bc4f2a125532aca32e87dac970576我是后来加入的16b28748ea4df4d9c2150843fecfba68";
alert("我是第1个脚本");
2.js
alert("我是第2个脚本");
修改HMTL中的代码为:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> <title>defer bug in IE=9 test</title> <script src="1.js" type="text/javascript" defer="defer"></script> <script src="2.js" type="text/javascript" defer="defer"></script> </head> <body> </body> </html>
正常情况下,浏览器中弹出框的顺序肯定是:我是第1个脚本-》我是第2个脚本,然而在IE5a634417e91f496f4f3dd9028dce2114 element defines both defer and async attributes, it will be processed as async (note: browsers that do not support async will directly ignore the async attribute)
[2] If the 3f1c4e4b6b16bbbd69b2ee476dc4f83a element only defines defer, it will be processed as a delayed script
[3] If the 3f1c4e4b6b16bbbd69b2ee476dc4f83a element does not define defer or async, it will be processed as normal, that is: the script will be loaded and executed immediately