亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

瀏覽器環境下JavaScript腳本加載與執行探析之defer與async特性

2019-11-20 10:48:10
字體:
來源:轉載
供稿:網友

defer和async特性相信是很多JavaScript開發者"熟悉而又不熟悉"的兩個特性,從字面上來看,二者的功能很好理解,分別是"延遲腳本"和"異步腳本"的作用。然而,以defer為例,一些細節問題可能開發者卻并不一定熟悉,比如:有了defer特性的腳本會延遲到什么時候執行;內部腳本和外部腳本是不是都能夠支持defer;defer后的腳本除了會延遲執行之外,還有哪些特殊的地方等等。本文結合已有的一些文章以及MDN文檔中對兩個特性的闡述,對defer和async進行更全面的研究和總結,希望能夠幫助開發者更好地掌握這兩個特性。

1 引言

在《瀏覽器環境下JavaScript腳本加載與執行探析之代碼執行順序》中我們提到過,JavaScript代碼的執行會阻塞頁面的解析渲染以及其他資源的下載,當然由于JavaScript是單線程語言,那就意味著在正常情況下,一個頁面中的JavaScript代碼只能按順序從上到下執行,當然,正如《瀏覽器環境下JavaScript腳本加載與執行探析之代碼執行順序》中我們分析的,在某些情況下,比如通過document.write進入腳本或者通過動態腳本技術引入腳本時,JavaScript代碼的執行順序不一定嚴格按照從上到下的順序,而defer和async也是我們所說的"非正常的情況"。

我們經常會說JavaScript的執行具有阻塞性,而在實際的開發中,我們通常最關心的阻塞,同時也是最影響用戶體驗的阻塞應該是以下幾個方面:

[1]頁面解析和渲染的阻塞

[2]我們寫的頁面初始化腳本(一般是監聽DOMContentLoaded事件所綁定的腳本,這部分腳本是我們希望最先執行的腳本,因為我們會把和用戶交互最相關的代碼寫在這里)

[3]頁面外部資源下載的阻塞(比如圖片)

如果我們有一個耗時的腳本操作,而這段腳本又阻塞了上面我們提到的這三個地方,那么這個網頁的性能或者用戶體驗就非常差了。

defer和async這兩個特性的初衷也是希望能夠解決或者緩解阻塞對于頁面體驗的影響,下面我們就來分析一下這兩個特性,我們主要從以下幾個方面來全方位了解這兩個特性:

[1]延遲或異步的腳本的執行時機是什么時候?對于頁面的阻塞情況如何?

[2]內部腳本和外部腳本是否都能夠實現延遲或異步?

[3]瀏覽器對這兩個特性的支持情況如何?有沒有相關的bug?

[4]使用了這兩個特性的腳本在使用時還有什么需要注意的地方?

2 defer特性

2.1 關于defer腳本的執行時機

defer特性是HTML4規范中定義的擴展特性,最初只有IE4+和firefox3.5+才支持,之后chrome等瀏覽器也增加了對它的支持,使用的方式為defer="defer"。defer意為延遲,也就是會延遲腳本的執行。正常情況下,我們引入的腳本會被立即下載和執行,而有了defer特性之后,腳本下載完畢后不會立即執行,而是等到頁面解析完畢之后再執行。我們看一下HTML4標準對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.

也就是說,如果設置了defer,那么就告訴用戶代理,這個腳本不會產生任何文檔內容,從而用戶代理可以繼續解析和渲染。我們再看一下MDN中對defer的關鍵描述:

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.

通過標準中的定義,我們可以明確,即:defer的腳本不會阻塞頁面的解析,而是等到頁面解析結束之后再執行,但是耗時的defer依然可能會阻塞外部資源的下載,那么它會阻塞DOMContentLoaded事件么?事實上,defer的腳本依然是在DOMContentLoaded事件之前執行的,因此它還是會阻塞DOMContentLoaded中的腳本。我們可以通過下圖來幫助理解defer腳本的執行時機:


根據標準中的定義,內部腳本不支持defer,而IE9及以下的瀏覽器則提供了內部腳本的defer支持。

2.2 defer的瀏覽器支持情況

下面我們來看一下defer特性的瀏覽器支持情況:


IE9及以下的瀏覽器存在一個bug,這個bug將在稍后的DEMO中進行詳細的說明。

2.3 DEMO:defer特性的功能驗證

我們模仿在Olivier Rochard在《the script defer attribute》使用的方式來驗證一下defer特性的功能:

首先我們準備了6個外部腳本:

1.js:

test += "我是head外部腳本/n";

2.js

test += "我是body外部腳本/n";

3.js

test += "我是底部外部腳本/n";

defer1.js

test += "我是head外部延遲腳本/n";

defer2.js

test += "我是body外部延遲腳本/n";

defer3.js

test += "我是底部外部延遲腳本/n";

HTML中的代碼為:

<!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里面的腳本/n";})window.onload = function(){test += "我是window.onload里面的腳本/n";var button = document.getElementById("test");button.onclick = function(){alert(test);}}</script></html> 

代碼中,為了方便實現DOMContentLoaded事件,我們引入了jQuery(之后的文章還會再介紹如何自己實現兼容的DOMContentLoaded),然后,我們在腳本的head內、body內部和body外部分別引入延遲腳本和正常腳本,并且通過一個全局的字符串來記錄每一段代碼的執行狀態,我們看一下各個瀏覽器中的執行結果:

IE7 IE9 IE10 CHROME firefox

我是head外部腳本
我是head內部腳本
我是body外部腳本
我是底部外部腳本
我是head外部延遲腳本
我是head延遲內部腳本
我是body外部延遲腳本
我是底部外部延遲腳本
我是DOMContentLoaded里面的腳本
我是window.onload里面的腳本

我是head外部腳本
我是head內部腳本
我是body外部腳本
我是底部外部腳本
我是head外部延遲腳本
我是head延遲內部腳本
我是body外部延遲腳本
我是底部外部延遲腳本
我是DOMContentLoaded里面的腳本
我是window.onload里面的腳本

我是head外部腳本
我是head延遲內部腳本
我是head內部腳本
我是body外部腳本
我是底部外部腳本
我是head外部延遲腳本
我是body外部延遲腳本
我是底部外部延遲腳本
我是DOMContentLoaded里面的腳本
我是window.onload里面的腳本

我是head外部腳本
我是head延遲內部腳本
我是head內部腳本
我是body外部腳本
我是底部外部腳本
我是head外部延遲腳本
我是body外部延遲腳本
我是底部外部延遲腳本
我是DOMContentLoaded里面的腳本
我是window.onload里面的腳本


我是head外部腳本我是head延遲內部腳本我是head內部腳本我是body外部腳本我是底部外部腳本我是head外部延遲腳本我是body外部延遲腳本我是底部外部延遲腳本我是DOMContentLoaded里面的腳本我是window.onload里面的腳本

從輸出的結果中我們可以確定,只有IE9及以下瀏覽器支持內部延遲腳本,并且defer后的腳本都會在DOMContentLoaded事件之前觸發,因此也是會堵塞DOMContentLoaded事件的。

2.4 DEMO:IE<=9的defer特性bug

從2.3節中的demo可以看出,defer后的腳本還是能夠保持執行順序的,也就是按照添加的順序依次執行。而在IE<=9中,這個問題存在一個bug:假如我們向文檔中增加了多個defer的腳本,而且之前的腳本中有appendChild,innerHTML,insertBefore,replaceChild等修改了DOM的接口調用,那么后面的腳本可能會先于該腳本執行??梢詤⒖糶ithub的issue:https://github.com/h5bp/lazyweb-requests/issues/42

我們通過DEMO驗證一下,首先修改1.js的代碼為(這段代碼只為模擬,事實上這段代碼存在極大的性能問題):

document.body.innerHTML = "<div id='div'>我是后來加入的</div>";
document.body.innerHTML += "<div id='div'>我是后來加入的</div>";
document.body.innerHTML += "<div id='div'>我是后來加入的</div>";
document.body.innerHTML += "<div id='div'>我是后來加入的</div>";
document.body.innerHTML += "<div id='div'>我是后來加入的</div>";
document.body.innerHTML += "<div id='div'>我是后來加入的</div>";
document.body.innerHTML += "<div id='div'>我是后來加入的</div>";
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個腳本,然而在IE<=9中,執行結果卻為:我是第2個腳本-》我是第1個腳本,驗證了這個bug。

2.5 defer總結

在總結之前,首先要說一個注意點:正如標準中提到的,defer的腳本中不應該出現document.write的操作,瀏覽器會直接忽略這些操作。

總的來看,defer的作用一定程度上與將腳本放置在頁面底部有一定的相似,但由于IE<=9中的bug,如果頁面中出現多個defer時,腳本的執行順序可能會被打亂從而導致代碼依賴可能會出錯,因此實際項目中很少會使用defer特性,而將腳本代碼放置在頁面底部可以替代defer所提供的功能。

3 async特性

3.1 關于async腳本的執行時機

async特性是HTML5中引入的特性,使用方式為:async="async",我們首先看一下標準中對于async特性的相關描述:

async:If the async attribute is present, then the script will be executed asynchronously, as soon as it is available.

需要指出,這里的異步,指的其實是異步加載而不是異步執行,也就是說,瀏覽器遇到一個async的script標簽時,會異步的去加載(個人認為這個過程主要是下載的過程),一旦加載完畢就會執行代碼,而執行的過程肯定還是同步的,也就是阻塞的。我們可以通過下圖來綜合理解defer和async:


這樣來看的話,async腳本的執行時機是無法確定的,因為腳本何時加載完畢也是不確定的。我們通過下面的demo來感受一下:

async1.js

alert("我是異步的腳本");

HTML代碼:

<!DOCTYPE html><html><head lang="en"><meta charset="UTF-8"><title>async attribute test</title><script src="/delayfile.php?url=http://localhost/js/load/async1.js&delay=2" async="async" type="text/javascript"></script><script>alert("我是同步的腳本");</script></head><body></body></html> 

這里我們借用了《瀏覽器環境下JavaScript腳本加載與執行探析之代碼執行順序》中的delayfile腳本來提供了一個延遲,這個腳本在支持async的瀏覽器中,彈框的順序一般是:我是同步的腳本-》我是異步的腳本。

3.2 async的瀏覽器支持情況

下面我們來看一下async特性的瀏覽器支持情況:

可以看到,只有IE10+才支持async特性,opera mini不支持async特性,另外,async是不支持內部腳本的。

3.3 async總結

async指的異步腳本,即腳本異步加載,加載的過程不會造成阻塞,但是async的腳本的執行時機是不確定的,而且執行的順序也是不確定的,因此使用async的腳本應該是不依賴于任何代碼的腳本(比如第三方統計代碼或廣告代碼),否則就會導致執行出錯。

4 defer和async的優先級問題

這一點比較好理解,標準中規定了:

[1]如果<script>元素同時定義了defer和async特性,則按async來處理(注意:對于不支持async的瀏覽器會直接忽略async特性)

[2]如果<script>元素只定義了defer,則按延遲腳本的方式處理

[3]如果<script>元素沒有定義defer也沒有定義async,則按正常情況處理,即:腳本立即加載和執行

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美日韩免费网站| 久久中文久久字幕| 亚洲国产精品久久久久秋霞蜜臀| 欧美网站在线观看| 精品欧美aⅴ在线网站| 国产精品免费一区二区三区都可以| 国产精品看片资源| 97国产一区二区精品久久呦| www.日韩.com| 日韩av最新在线观看| 欧美精品18videos性欧美| 热re99久久精品国产66热| 国产成人精品网站| 日韩精品高清在线观看| 欧美成人精品一区二区三区| 成人免费大片黄在线播放| 亚洲成人精品视频| 欧美性精品220| 91色在线观看| 欧美精品午夜视频| 欧美性猛交xxxx免费看久久久| 九九久久精品一区| 久久99精品久久久久久噜噜| 亚洲美女视频网| 国产成人97精品免费看片| 热re91久久精品国99热蜜臀| 亚洲韩国欧洲国产日产av| 国产精品极品美女粉嫩高清在线| 亚洲国产美女精品久久久久∴| 亚州精品天堂中文字幕| 久久6免费高清热精品| 欧美激情第6页| 国产一区二区三区精品久久久| 精品丝袜一区二区三区| 国产精品看片资源| 国产精品一区二区三区久久| 国产精品7m视频| 日本国产欧美一区二区三区| 国产精品免费网站| 日韩亚洲成人av在线| 成人激情视频网| 欧美日韩精品国产| 欧美激情亚洲视频| 亚洲日本中文字幕| 亚洲精品电影在线| 成人激情视频在线播放| 欧美一级片在线播放| 亚洲精品美女在线观看播放| 97色在线视频观看| 欧美日韩在线免费| 这里只有视频精品| 国产精品日韩欧美| 中文字幕国产精品久久| 91性高湖久久久久久久久_久久99| 伊人一区二区三区久久精品| 亚洲精品免费在线视频| 国内精品模特av私拍在线观看| 日韩av一区二区在线观看| 亚洲视频免费一区| 午夜精品免费视频| 欧美在线国产精品| 深夜福利国产精品| 欧美裸体视频网站| 久久夜色撩人精品| 96sao精品视频在线观看| 91地址最新发布| 国产69精品久久久久久| 国产精品av免费在线观看| 欧美噜噜久久久xxx| 色老头一区二区三区在线观看| 精品日本高清在线播放| 成人免费在线网址| 国产日韩欧美在线视频观看| 日韩一区av在线| 北条麻妃一区二区在线观看| 俺去亚洲欧洲欧美日韩| 日韩成人在线免费观看| 欧美又大又硬又粗bbbbb| 一区二区亚洲欧洲国产日韩| 亚洲欧美成人在线| 在线观看欧美成人| 高清一区二区三区日本久| 久久久在线免费观看| 欧美壮男野外gaytube| 久久精品国产成人| 美女国内精品自产拍在线播放| 久久国产精品网站| 日本久久亚洲电影| 成人精品视频99在线观看免费| 国产精品久久久久久久久久三级| 日韩电影免费在线观看| 日韩精品免费看| 亚洲色图美腿丝袜| 亚洲久久久久久久久久久| 中文字幕日韩在线播放| 欧美性xxxx极品hd欧美风情| 久久九九全国免费精品观看| 日韩中文在线观看| 亚洲第一天堂无码专区| 欧美天天综合色影久久精品| 亚洲人成网在线播放| 国产成人亚洲综合91| 97人人爽人人喊人人模波多| 日韩女优人人人人射在线视频| 亚洲深夜福利视频| 亚洲性线免费观看视频成熟| 亚洲天堂av在线免费观看| 国内揄拍国内精品少妇国语| 亚洲欧美激情在线视频| 欧美黑人xxx| 欧美精品激情在线| 国产一区二区动漫| 97精品免费视频| 伊人亚洲福利一区二区三区| 国产精品免费一区二区三区都可以| 色伦专区97中文字幕| 国产日韩综合一区二区性色av| 亚洲国产精品一区二区三区| 亚洲精品国产免费| 精品久久久久久久久国产字幕| 国产成人久久久精品一区| 国产精品69精品一区二区三区| 亚洲激情在线观看| 91国产视频在线| 91情侣偷在线精品国产| 亚洲欧美激情在线视频| 久久成人精品一区二区三区| 色综合久综合久久综合久鬼88| 国产a级全部精品| 欧美成人自拍视频| 日韩亚洲欧美中文高清在线| 精品视频在线播放色网色视频| 国产精品手机播放| 欧美精品videossex88| 国产欧美精品一区二区| 另类美女黄大片| 日韩欧美在线看| 久久久久久免费精品| 97香蕉超级碰碰久久免费的优势| 91日韩在线视频| 777午夜精品福利在线观看| 国产99久久精品一区二区永久免费| 亚洲裸体xxxx| 亚洲视频国产视频| 亚洲人成在线观看| 国产精品精品一区二区三区午夜版| 成人美女av在线直播| 另类图片亚洲另类| 欧美黑人巨大xxx极品| 亚洲精品久久久久久久久| 亚洲一区二区在线播放| 精品国产精品三级精品av网址| 欧美成人h版在线观看| 一区二区三区四区精品| 日本精品视频在线播放| 日韩亚洲一区二区| 日韩在线免费观看视频| www.99久久热国产日韩欧美.com| 精品在线小视频| 欧美巨大黑人极品精男| 国产精品视频久久久| 国产成人亚洲综合| 欧美激情2020午夜免费观看| 两个人的视频www国产精品|