成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

腳本的加載和執(zhí)行

TANKING / 909人閱讀

摘要:現(xiàn)在對(duì)的使用非常普遍,任何一個(gè)站點(diǎn)都會(huì)請(qǐng)求大量的腳本,而加載和執(zhí)行的方式也是各不相同,希望讀完這篇文章可以對(duì)常用的加載和執(zhí)行方式有一個(gè)整體的認(rèn)識(shí)??偨Y(jié)上文主要介紹了動(dòng)態(tài)創(chuàng)建腳本和的方式去創(chuàng)建異步加載和執(zhí)行腳本的方式。

在打開(kāi)一個(gè)站點(diǎn)的時(shí)候,瀏覽器會(huì)去加載各種資源?,F(xiàn)在對(duì)JS的使用非常普遍,任何一個(gè)站點(diǎn)都會(huì)請(qǐng)求大量的JS腳本,而加載和執(zhí)行的方式也是各不相同,希望讀完這篇文章可以對(duì)常用的加載和執(zhí)行方式有一個(gè)整體的認(rèn)識(shí)。

首先介紹的是html中直接使用

// 使用script的src屬性引用外部腳本

這種方式在主流的瀏覽器可以是并行加載的,但是執(zhí)行腳本的順序還是同步的,再加上瀏覽器是順序解析頁(yè)面,所以對(duì)于腳本的位置是有一定講究的:


如果腳本B需要使用到腳本A中的數(shù)據(jù)(比如fn或者變量),那腳本B必須放在腳本A后面。

因?yàn)閳?zhí)行引擎是單線程的,所以在執(zhí)行JS的時(shí)候會(huì)阻塞DOM的渲染,導(dǎo)致頁(yè)面長(zhǎng)時(shí)間空白。如果不想的話可以考慮把JS放在文檔的后面(比如body標(biāo)簽的底部)。

一個(gè)外鏈腳本就涉及到一個(gè)請(qǐng)求,再小的請(qǐng)求肯定都會(huì)有性能開(kāi)銷,比如請(qǐng)求頭,網(wǎng)絡(luò)時(shí)延等等。所以在優(yōu)化站點(diǎn)性能的時(shí)候減少外鏈也是要考慮的一個(gè)點(diǎn)。

【注】:可并行加載的瀏覽器包括:IE8+、firefox3.5+、safari4+和chrome2+。不同瀏覽器對(duì)于同一個(gè)域名下的最大連接數(shù)有不同的限制,基本在6個(gè)左右。具體可以參見(jiàn)這篇文章。

在程序的世界中,很多場(chǎng)景下同步阻塞就意味著性能問(wèn)題。在這些場(chǎng)景下其實(shí)無(wú)阻塞腳本就可以搞定,主進(jìn)程還是去干當(dāng)前最主要的事情,即加載和渲染DOM,而無(wú)阻塞的腳本可以等到頁(yè)面加載完再去加載執(zhí)行,這些場(chǎng)景正是性能優(yōu)化的點(diǎn)。

這就引申出來(lái)了幾種無(wú)阻塞腳本的方案。

方案一:defer屬性 【w3c】【MDN】

這個(gè)屬性的是承諾用src引的腳本中不會(huì)修改DOM。放心的讓這個(gè)腳本延遲執(zhí)行吧。具體延遲到文檔完成解析后,觸發(fā) DOMContentLoaded 事件前執(zhí)行。

【注1】執(zhí)行是被延遲了,但是下載還是根據(jù)script在頁(yè)面中的位置。解析到時(shí)會(huì)去并行下載,但是不會(huì)執(zhí)行。
【注2】由上述定義可以看出來(lái)需由src的存在,對(duì)于內(nèi)嵌的腳本是無(wú)效的。
【注3】配了defer屬性的腳本之間是按照順序執(zhí)行的

【測(cè)試】 chrome 64.0.3282.119

   
   
   
   
// demo.js
console.log("inner demo.js");

結(jié)果:

方案二:async屬性 【w3c】【MDN】

配置了async屬性是告訴瀏覽器,這個(gè)腳本異步去并行加載,加載完立即異步執(zhí)行,但是加載的時(shí)機(jī)是不確定的,所以這個(gè)屬性比defer更開(kāi)放。相關(guān)測(cè)試代碼

【注1】因?yàn)楫惒郊虞d完就立即異步執(zhí)行,所以配了這個(gè)屬性的腳本之間的關(guān)系也是不確定的。所以不能存在依賴async腳本內(nèi)容的情況。
【注2】執(zhí)行的時(shí)機(jī)智能確定在load事件之前,和DOMContentLoaded的時(shí)機(jī)不能確定
【注3】?jī)?yōu)先級(jí)是高于defer的
【注4】和defer一樣,對(duì)內(nèi)嵌腳本無(wú)效;不能有document.write改寫(xiě)dom的代碼
方案三:動(dòng)態(tài)腳本

動(dòng)態(tài)腳本是我們比較常用的異步加載和執(zhí)行JS的方式。這種實(shí)現(xiàn)要特別注意瀏覽器的兼容性。簡(jiǎn)單的實(shí)現(xiàn)方式如下:

function loadJs(url,callback) {
    var callback = callback || (() => {});
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = url;

    if(script.readyState){ //IE
        script.onreadystatechange = function () {
            if(script.readyState == "loaded" || script.readyState == "complete"){
                console.log("inner onreadystatechange");
                script.onreadystatechange = null;
                callback();
            }
        };
    } else {
        script.onload = function () {
            console.log("inner onload");
            callback();
        };
    }

    document.getElementsByTagName("head")[0].appendChild(script); // 開(kāi)始下載并執(zhí)行
}

loadJs("./server.js");

這種創(chuàng)建的方式,文件在該元素被添加到頁(yè)面時(shí)開(kāi)始下載,加載完開(kāi)始執(zhí)行,并且文件的下載和執(zhí)行過(guò)程不會(huì)阻塞其它進(jìn)程。可以認(rèn)為這種創(chuàng)建默認(rèn)加了async屬性。我們還可以通過(guò)設(shè)置async = false的方式取消異步的特性。正因?yàn)檫@個(gè)特性,絕大多數(shù)場(chǎng)景下都是有益的,但是當(dāng)我們想使用這種方式去加載多個(gè)JS時(shí),并且有先后順序的時(shí)候,可以嘗試在callbak里去迭代發(fā)請(qǐng)求。

loadJs("f1.js",()=>{
    loadJs("f2.js",()=>{
        loadJs(xxx);
    })
});
方案四:XMLHttpRequest(XHR)注入腳本
搞過(guò)Ajax的對(duì)XHR應(yīng)該都很熟悉了,在這就不詳細(xì)介紹了,需要的去Google一把。

XHR主要是請(qǐng)求腳本,然后我們可以控制請(qǐng)求回來(lái)的腳本,在我們需要的時(shí)候通過(guò)上述動(dòng)態(tài)創(chuàng)建腳本的方式注入到頁(yè)面中。這種方式最大的好處就是兼容性好。弊端也很明顯,必須同源。下面是一個(gè)簡(jiǎn)單實(shí)現(xiàn),沒(méi)有考慮在創(chuàng)建xhr的兼容性,比如ActiveXObject,有需要的可以去google一把:

var xhr = new XMLHttpRequest(); // 創(chuàng)建xhr對(duì)象
xhr.open("get","./server.js",true); // 初始化一個(gè)請(qǐng)求, 支持CRUD
xhr.onreadystatechange = function () { 
    if(xhr.readyState == 4){
        if(xhr.status >= 200 && xhr.status < 3000 || xhr.status == 304){
            var script = document.createElement("script");
            script.type = "text/javascript";
            script.text = xhr.responseText;
            document.body.appendChild(script);
        }
    }
}
xhr.send(null); // 發(fā)送請(qǐng)求

這地方說(shuō)明一下xhr.status:

狀態(tài) 描述
0 UNSENT (未打開(kāi)) open()方法還未被調(diào)用.
1 OPENED (未發(fā)送) open()方法已經(jīng)被調(diào)用.
2 HEADERS_RECEIVED (已獲取響應(yīng)頭) send()方法已經(jīng)被調(diào)用, 響應(yīng)頭和響應(yīng)狀態(tài)已經(jīng)返回
3 LOADING (正在下載響應(yīng)體) 響應(yīng)體下載中; responseText中已經(jīng)獲取了部分?jǐn)?shù)據(jù).
4 DONE (請(qǐng)求完成) 整個(gè)請(qǐng)求過(guò)程已經(jīng)完畢.
其它方案: document.write

對(duì)于document.write,一般都不推薦使用的,主要是因?yàn)榇嬖?b>write方法的腳本可能會(huì)在解析的過(guò)程中修改DOM,導(dǎo)致一些腳本無(wú)法預(yù)加載,甚至?xí)?dǎo)致一些已經(jīng)預(yù)解析和預(yù)加載失效。網(wǎng)上也很多關(guān)于為什么要避免使用document.write的文章,感興趣的可以去google一把。

innerHtml

對(duì)于innerHtmlouterHTML, 只會(huì)以字符串的形式來(lái)承載,不會(huì)去執(zhí)行對(duì)應(yīng)的腳本的。

總結(jié):上文主要介紹了動(dòng)態(tài)創(chuàng)建腳本和XHR的方式去創(chuàng)建異步加載和執(zhí)行腳本的方式。在某些性能調(diào)優(yōu)的情況下還是很有用的,而XHR更是Ajax的核心。

參考

高性能Javascript

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/107416.html

相關(guān)文章

  • 文檔加載

    摘要:完成文檔和所有子資源已完成加載。在中可以使用事件來(lái)檢測(cè)文檔是否加載完畢在更早的版本中可以通過(guò)每隔一段時(shí)間執(zhí)行一次來(lái)檢測(cè)這一狀態(tài),因?yàn)檫@條代碼在加載完畢之前執(zhí)行時(shí)會(huì)拋出錯(cuò)誤。 Document.readyState Document.readyState 屬性描述了文檔的加載狀態(tài)。當(dāng)readyState的值變化時(shí),document對(duì)象上的readystatechange事件將被觸發(fā)。 r...

    beita 評(píng)論0 收藏0
  • 前端優(yōu)化-Javascript篇(2.異步加載腳本)

    摘要:下面介紹非阻塞加載腳本技術(shù)也就是異步加載。非阻塞加載腳本關(guān)于的一篇好文目前所有瀏覽器都支持屬性,但是和中只有在加載外部腳本時(shí)才會(huì)生效,行內(nèi)腳本使用是沒(méi)有作用的。在中,只有外部腳本才會(huì)發(fā)生阻塞。   上篇博客說(shuō)過(guò)腳本后置可以使頁(yè)面更快的加載,可是這樣的優(yōu)化還是有限的,如果腳本需要執(zhí)行一個(gè)耗時(shí)的操作,就算后置了它還是會(huì)阻塞后續(xù)腳本加載和執(zhí)行并且阻塞整個(gè)頁(yè)面。下面介紹非阻塞加載腳本技術(shù)也就是...

    wpw 評(píng)論0 收藏0
  • 頁(yè)面生命周期:DOMContentLoaded, load, beforeunload, unloa

    摘要:所以有可能在所有腳本執(zhí)行完畢后觸發(fā)。如果用戶即將離開(kāi)頁(yè)面或者關(guān)閉窗口時(shí),事件將會(huì)被觸發(fā)以進(jìn)行額外的確認(rèn)。狀態(tài)表示事件即將被觸發(fā)??偨Y(jié)頁(yè)面事件的生命周期事件在樹(shù)構(gòu)建完畢后被觸發(fā),我們可以在這個(gè)階段使用去訪問(wèn)元素。 頁(yè)面生命周期:DOMContentLoaded, load, beforeunload, unload 原文地址:http://javascript.info/onload.....

    lx1036 評(píng)論0 收藏0
  • 頁(yè)面生命周期:DOMContentLoaded, load, beforeunload, unloa

    摘要:所以有可能在所有腳本執(zhí)行完畢后觸發(fā)。如果用戶即將離開(kāi)頁(yè)面或者關(guān)閉窗口時(shí),事件將會(huì)被觸發(fā)以進(jìn)行額外的確認(rèn)。狀態(tài)表示事件即將被觸發(fā)??偨Y(jié)頁(yè)面事件的生命周期事件在樹(shù)構(gòu)建完畢后被觸發(fā),我們可以在這個(gè)階段使用去訪問(wèn)元素。 頁(yè)面生命周期:DOMContentLoaded, load, beforeunload, unload 原文地址:http://javascript.info/onload.....

    luckyyulin 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<