網(wǎng)站性能優(yōu)化(三)異步加載腳本

原則上來說,HTML在使用<script>標(biāo)簽加載外部腳本文件時捐韩,會順序下載退唠,順序執(zhí)行,并阻礙其他資源文件的下載荤胁,比如圖片(當(dāng)然瞧预,如今主流瀏覽器是可以實現(xiàn)JS和CSS文件并行下載)。

code1.png

(在Chrome下測試仅政,三張圖片只會有兩張被阻塞垢油。我猜測,Chrome是想做某些優(yōu)化的已旧,但是秸苗,顯然優(yōu)化的不夠徹底召娜。不同瀏覽器表現(xiàn)還是不一致的)


loading1.png

為了加速頁面渲染运褪,不讓腳本文件阻塞其他資源下載,可以考慮“異步加載腳本”的技術(shù)。

后續(xù)的測試都基于Chrome瀏覽器(版本56.0.2924.87)秸讹。

1. Script DOM Element

這恐怕是最常見的異步加載腳本方法檀咙,即,動態(tài)創(chuàng)建一個script標(biāo)簽璃诀,并設(shè)置其src值弧可。如下:

function createScript(url){
  var scrElem = document.createElement('script');
  srcElem.src = url;
  document.getElementsByTagName('head')[0].appendChild(scrElem);
}

createScript方式加載JS文件,不會阻塞下載其他資源劣欢。

loading2.png

但是這種方式會阻塞window.onload事件棕诵,參考chrome developer timeline:

timeline-script.png

優(yōu)點::

  • 支持跨域加載腳本文件
  • 兼容性最好、普適性最高的方案

缺點::

  • 腳本無序執(zhí)行
  • 會阻塞onload事件

2. XMLHttpRequest

通過XMLHttpRequest的方式下載腳本文件凿将,然后使用eval或者動態(tài)添加<script>標(biāo)簽并設(shè)置其text屬性來執(zhí)行腳本校套。

// 不考慮IE
var xhrObj = new XMLHttpRequest();
xhrObj .onreadystatechange = function(){
  if (xhrObj .readyState == 4) {
    eval(xhrObj.responseText);  
    或者
    var scrElem = document.createElement('script');
    srcElem.text= xhrObj.responseText;
    document.getElementsByTagName('head')[0].appendChild(scrElem);
  }
}
xhrObj .open('GET', 'a.js', true);
xhrObj .send('');

稍微修改下上面的例子:

index.html

<html>
...
<body>
  <script type="application/javascript" src="js1.js"></script>
</body>
</html>

js1.js

var xhrObj = new XMLHttpRequest();
xhrObj .onreadystatechange = function(){
    if (xhrObj .readyState == 4) {
        var scrElem = document.createElement('script');
        srcElem.text= xhrObj.responseText;
        document.getElementsByTagName('head')[0].appendChild(scrElem);
    }
};
xhrObj .open('GET', 'js2.js', true);
xhrObj .send('');

查看chrome developer timeline:

timeline-xhr.png

優(yōu)點::

  • 將腳本下載和腳本執(zhí)行分離開,可以在適當(dāng)?shù)臅r候再執(zhí)行腳本牧抵。
  • 不會阻塞onload事件

缺點::

  • 通過XMLHttpRequest獲取的腳本文件必須和主頁面是同一個域名下笛匙。也就是說,不支持跨域下載腳本犀变。因此不適合加載第三方文件妹孙。
  • 腳本無序執(zhí)行。

3. Script defer和async

兩者都支持異步加載文件获枝,不同之處是蠢正,defer會在全部資源下載完畢后才執(zhí)行JS文件;async在腳本文件下載完就立刻執(zhí)行映琳,并且机隙,async模式加載的JS文件無法依序執(zhí)行,對于有順序依賴的腳本來說萨西,不應(yīng)該采用這種方式有鹿。defer相對友好一些,并可以保證JS文件按照順序執(zhí)行谎脯。

稍微對程序做些修改:


code2.png
loading3.png

優(yōu)點::

  • defer和async優(yōu)點:支持跨域加載腳本文件葱跋。
  • defer優(yōu)點:可以保證JS文件按照順序執(zhí)行。

缺點::

  • defer和async缺點:IE10以上(包括IE10)才支持源梭。
  • async缺點:JS文件無法依序執(zhí)行娱俺。
  • 會阻塞onload事件

4. Script in Iframe

創(chuàng)建了一個隱藏的iframe標(biāo)簽,設(shè)置其src值為JS代碼废麻,然后插入到主頁面中荠卷。

這種方式在實際項目中很少用到,因為iframe是開銷最高的DOM元素烛愧。常用場景是顯示廣告(廣告一般需要運行在隔離環(huán)境中油宜,iframe很合適)掂碱。

<iframe src=“a.html” frameborder="1" name="rightFrame" id="rightFrame"></iframe>

注意,src的值是a.html慎冤,而不是a.js疼燥,因為iframe默認(rèn)其返回值為HTML文檔。所以需要在HTML文檔中把外部腳本轉(zhuǎn)成行內(nèi)腳本蚁堤。

和XMLHttpRequest一樣醉者,iframe不支持跨域加載腳本,且腳本無序執(zhí)行披诗。

5. 小結(jié)

異步加載腳本還普遍存在另一個問題:無法保持多個腳本的執(zhí)行順序(除了defer)撬即。
為了腳本依序執(zhí)行,可以采用如下方法:
1)定時器
利用setTimeoutsetInterval監(jiān)控第一個腳本執(zhí)行情況呈队,一旦發(fā)現(xiàn)被執(zhí)行完搞莺,再繼續(xù)執(zhí)行下一個腳本。

  1. Script Onload
    利用script元素的onloadonreadystatechange事件處理程序掂咒,例子如下:
<script>
    var scrElem = document.createElement('script');
    scrElem.src = 'a.js';
    scrElem.onloadDone = false;
 
    scrElem.onload = function () {
        scrElem.onloadDone = true;
        // 執(zhí)行第二個腳本
    };
    //針對IE瀏覽器
    scrElem.onreadystatechange = function () {
        if ((scrElem.readyState === 'loaded' || scrElem.readyState === 'complete') && !scrElem.onloadDone) {
            scrElem.onloadDone = true;
            //執(zhí)行第二個腳本
        }
    };
    document.getElementsByTagName('head')[0].appendChild(scrElem);
</script>

注意:script.onload/onreadystatechange事件同樣會阻塞window.onload

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末才沧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子绍刮,更是在濱河造成了極大的恐慌温圆,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件孩革,死亡現(xiàn)場離奇詭異岁歉,居然都是意外死亡,警方通過查閱死者的電腦和手機膝蜈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進店門锅移,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人饱搏,你說我怎么就攤上這事非剃。” “怎么了推沸?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵备绽,是天一觀的道長。 經(jīng)常有香客問我鬓催,道長肺素,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任宇驾,我火速辦了婚禮倍靡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘课舍。我一直安慰自己塌西,他們只是感情好蜗顽,可當(dāng)我...
    茶點故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著雨让,像睡著了一般。 火紅的嫁衣襯著肌膚如雪忿等。 梳的紋絲不亂的頭發(fā)上栖忠,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天,我揣著相機與錄音贸街,去河邊找鬼庵寞。 笑死,一個胖子當(dāng)著我的面吹牛薛匪,可吹牛的內(nèi)容都是我干的捐川。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼逸尖,長吁一口氣:“原來是場噩夢啊……” “哼古沥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起娇跟,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤岩齿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后苞俘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盹沈,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年吃谣,在試婚紗的時候發(fā)現(xiàn)自己被綠了乞封。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,438評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡岗憋,死狀恐怖肃晚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情仔戈,我是刑警寧澤陷揪,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站杂穷,受9級特大地震影響悍缠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜耐量,卻給世界環(huán)境...
    茶點故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一飞蚓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧廊蜒,春花似錦趴拧、人聲如沸溅漾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽添履。三九已至,卻和暖如春脑又,著一層夾襖步出監(jiān)牢的瞬間暮胧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工问麸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留往衷,地道東北人。 一個月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓严卖,卻偏偏與公主長得像席舍,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子哮笆,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,446評論 2 359

推薦閱讀更多精彩內(nèi)容