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

首頁 > 編程 > JavaScript > 正文

JavaScript異步加載淺析

2019-11-20 13:34:43
字體:
來源:轉載
供稿:網友

前言

關于JavaScript腳本加載的問題,相信大家碰到很多。主要在幾個點――

1> 同步腳本和異步腳本帶來的文件加載、文件依賴及執行順序問題
2> 同步腳本和異步腳本帶來的性能優化問題


深入理解腳本加載相關的方方面面問題,不僅利于解決實際問題,更加利于對性能優化的把握并執行。
 
先看隨便一個script標簽代碼――


復制代碼 代碼如下:

<script src="js/myApp.js"></script>


如果放在<head>上面,會阻塞所有頁面渲染工作,使得用戶在腳本加載完畢并執行完畢之前一直處于“白屏死機”狀態。而<body>末尾的打腳本只會讓用戶看到毫無生命力的靜態頁面,原本應該進行客戶端渲染的地方卻散布著不起作用的控件和空空如也的方框。拿一個測試用例――

復制代碼 代碼如下:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>異步加載script</title>
    <script src="js/test.js"></script>
</head>
<body>
    <div>我是內容</div>
    <img src="img/test.jpg">
</body>
</html>

其中,test.js中的內容――


復制代碼 代碼如下:

alert('我是head里面的腳本代碼,執行這里的js之后,才開始進行body的內容渲染!');


我們會看到,alert是一個暫停點,此時,頁面是空白的。但是要注意,此時整個頁面已經加載完畢,如果body中包含某些src屬性的標簽(如上面的img標簽),此時瀏覽器已經開始加載相關內容了??傊⒁猕D―js引擎和渲染引擎的工作時機是互斥的(一些書上叫它為UI線程)。

因此,我們需要――那些負責讓頁面更好看、更好用的腳本應該立即加載,而那些可以待會兒再加載的腳本稍后再加載。

一、腳本延遲執行

現在越來越流行把腳本放在頁面<body>標簽的尾部。這樣,一方面用戶可以更快地看到頁面,另一方面腳本可以直接操作已經加載完成的dom元素。對于大多數腳本而言,這次“搬家”是個巨大的進步。該頁面模型如下――


復制代碼 代碼如下:

<!DOCTYPE html>
<html>
<head lang="en">
    <!--metadata and scriptsheets go here-->
    <script src="headScript.js"></script>
</head>
<body>
    <!--content goes here-->
    <script src="bodyScript.js"></script>
</body>
</html>

這確實大大加快了頁面的渲染時間,但是注意一點,這可能讓用戶有機會在加載bodyScript之前與頁面交互。源于瀏覽器在加載完整個文檔之前無法加載這些腳本,這對那些通過慢速連接傳送的大型文檔來說會是一大瓶頸。

理想情況下,腳本的加載應該與文檔的加載同時進行,并且不影響DOM的渲染。這樣,一旦文檔就緒就可以運行腳本,因為已經按照<script>標簽的次序加載了相應腳本。

我們使用defer便能夠完成這樣的需求,即――


復制代碼 代碼如下:

<script src="deferredScript.js"></script>


添加defer屬性相當于告訴瀏覽器:請馬上開始加載這個腳本吧,但是,請等到文檔就緒且此前所有具有defer屬性的腳本都結束運行之后再運行它。

這樣,在head標簽里放入延遲腳本,技能帶來腳本置于body標簽時的所有好處,又能讓大文檔的加載速度大幅提升。此時的頁面模式便是――


復制代碼 代碼如下:

<!DOCTYPE html>
<html>
<head lang="en">
    <!--metadata and scriptsheets go here-->
    <script src="headScript.js"></script>
    <script src="deferredScript.js" defer></script>
</head>
<body>
    <!--content goes here-->
</body>
</html>

但是并非所有的瀏覽器都支持defer(對于一些modern瀏覽器,如果聲明defer,其內部腳本將不會執行document.write及DOM渲染操作。IE4+均支持defer屬性)。這意味著,如果想確保自己的延遲腳本能在文檔加載后運行,就必須將所有延遲腳本的代碼都封裝在諸如jQuery之$(document).ready之類的結構中。這是值得的,因為差不多97%的訪客都能享受到并行加載的好處,同時另外3%的訪客仍然能使用功能完整的JavaScript。

二、腳本的完全并行化

讓腳本的加載及執行再快一步,我不想等到defer腳本一個接著一個運行(defer讓我們想到一種靜靜等待文檔加載的有序排隊場景),更不想等到文檔就緒之后才運行這些腳本,我想要盡快加載并且盡快運行這些腳本。這里也就想到了HTML5的async屬性,但是要注意,它是一種混亂的無政府狀態。

例如,我們加載兩個完全不相干的第三方腳本,頁面沒有它們也運行得很好,而且也不在乎它們誰先運行誰后運行。因此,對這些第三方腳本使用async屬性,相當于一分錢沒花就提升了它們的運行速度。

async屬性是HTML5新增的。作用和defer類似,即允許在下載腳本的同時進行DOM的渲染。但是它將在下載后盡快執行(即JS引擎空閑了立馬執行),不能保證腳本會按順序執行。它們將在onload 事件之前完成。

Firefox 3.6、Opera 10.5、IE 9 和 最新的Chrome 和 Safari 都支持 async 屬性??梢酝瑫r使用 async 和 defer,這樣IE 4之后的所有 IE 都支持異步加載,但是要注意,async會覆蓋掉defer。

那么此時的頁面模型如下――

復制代碼 代碼如下:

<!DOCTYPE html>
<html>
<head lang="en">
    <!--metadata and scriptsheets go here-->
    <script src="headScript.js"></script>
    <script src="deferredScript.js" defer></script>
</head>
<body>
    <!--content goes here-->
    <script src="asyncScript1.js" async defer></script>
    <script src="asyncScript2.js" async defer></script>
</body>
</html>

要注意這里的執行順序――各個腳本文件加載,接著執行headScript.js,緊接著在DOM渲染的同時會在后臺加載defferedScript.js。接著在DOM渲染結束時將運行defferedScript.js和那兩個異步腳本,要注意對于支持async屬性的瀏覽器而言,這兩個腳本將做無序運行。

三、可編程的腳本加載

盡管上面兩個腳本屬性的功能非常吸引人,但是由于兼容性的問題,應用并不是很廣泛。故此,我們更多使用腳本加載其他腳本。例如,我們只想給那些滿足一定條件的用戶加載某個腳本,也就是經常提到的“懶加載”。

在瀏覽器API層面,有兩種合理的方法來抓取并運行服務器腳本――

1> 生成ajax請求并用eval函數處理響應

2> 向DOM插入<script>標簽

后一種方式更好,因為瀏覽器會替我們操心生成HTTP請求這樣的事。再者,eval也有一些實際問題:泄露作用域,調試搞得一團糟,而且還可能降低性能。因此,想要加載名為feture.js的腳本,我們應該使用類似下面的代碼:


復制代碼 代碼如下:

var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = 'feature.js';
head.appendChild(script);

當然,我們要處理回調監聽,HTML5規范定義了一個可以綁定回調的onload屬性。


復制代碼 代碼如下:

script.onload = function() {
    console.log('script loaded ...');
}


不過,IE8及更老的版本并不支持onload,它們支持的是onreadystatechange。而且,對于錯誤處理仍然千奇百怪。在這里,可以多參考一些流行的校本加載庫,如labjs、yepnope、requirejs等。

如下,自己封裝了一個簡易loadjs文件――


復制代碼 代碼如下:

var loadJS = function(url,callback){
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.src = url;
    script.type = "text/javascript";
    head.appendChild( script);

    // script 標簽,IE下有onreadystatechange事件, w3c標準有onload事件
    // IE9+也支持 W3C標準的onload
    var ua = navigator.userAgent,
        ua_version;
    // IE6/7/8
    if (/MSIE ([^;]+)/.test(ua)) {
        ua_version = parseFloat(RegExp["$1"], 10);
        if (ua_version <= 8) {
            script.onreadystatechange = function(){
                if (this.readyState == "loaded" ){
                    callback();
                }
            }
        } else {
            script.onload = function(){
                callback();
            };
        }
    } else {
        script.onload = function(){
            callback();
        };
    }
};

對于document.write的方式異步加載腳本,在這里就不說了,現在很少有人這么干了,因為瀏覽器差異性實在是搞得頭大。

要注意,使用 Image 對象異步預加載 js 文件,里面的js代碼將不會被執行。

最后,談一下requirejs中的異步加載腳本。

requirejs不會保證按順序運行目標腳本,只是保證它們的運行次序能滿足各自的依賴性要求。從而我們確保了盡快的并行加載所有腳本,并有條不紊的按照依賴性拓撲結構去執行這些腳本。

 

四、總結

OK,談到這兒,異步加載腳本的陳述也就完了。我再次亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

久久久国产成人精品| 在线免费看av不卡| 91久久久亚洲精品| 亚洲欧美成人精品| 菠萝蜜影院一区二区免费| 亚洲成人av在线| 国产91精品黑色丝袜高跟鞋| 午夜精品视频网站| 亚洲成人av在线播放| 亚洲欧美日韩精品久久奇米色影视| 亚洲欧美日韩国产中文专区| 日韩在线播放av| 欧美人交a欧美精品| 日韩电影在线观看免费| 久久成人国产精品| 国产美女精品免费电影| 亚洲一区二区少妇| 亚洲一区亚洲二区| 狠狠久久五月精品中文字幕| 国产精品日韩精品| 97免费中文视频在线观看| 亚洲色图50p| 91av中文字幕| 欧美性在线视频| 日本国产欧美一区二区三区| 久久免费少妇高潮久久精品99| 亚洲欧洲一区二区三区久久| 精品福利在线看| 亚洲性线免费观看视频成熟| 国产香蕉97碰碰久久人人| 亚洲欧美在线免费观看| 成人免费视频97| 亚洲精品免费一区二区三区| 久久久久999| 午夜免费在线观看精品视频| 久久91超碰青草是什么| 欧美性猛交xxxx黑人猛交| 社区色欧美激情 | 欧美激情免费看| 国产日韩精品一区二区| 国产日韩中文在线| 成人午夜在线观看| 91久久在线视频| 亚洲天堂一区二区三区| 亚洲免费成人av电影| 国产精品久久久久久久久久小说| 日本免费久久高清视频| 91精品久久久久久久久久久| 精品国产成人在线| 欧美亚洲成人网| 亚洲在线免费视频| 日韩免费观看在线观看| 日本成人黄色片| 一区二区欧美日韩视频| 中文字幕9999| 国产免费一区视频观看免费| 日韩二区三区在线| 97超级碰碰碰| 中文字幕久久精品| 午夜精品久久久久久久99热浪潮| 国产精品私拍pans大尺度在线| 欧美丝袜一区二区三区| 久久久久久久久国产| 久久精品国产96久久久香蕉| 欧美成人自拍视频| 日韩欧美一区二区三区久久| 97视频免费看| 亚洲情综合五月天| 欧美大荫蒂xxx| 久久成人精品视频| 久久精品成人一区二区三区| 久久精品国产99国产精品澳门| 亚洲精品www| 国产精品av电影| 国产丝袜一区二区| 成人久久久久爱| 久久影院中文字幕| 岛国av一区二区在线在线观看| 亚洲成av人影院在线观看| 欧美成人黄色小视频| 一个人看的www欧美| 久久精品电影网| 中文字幕欧美日韩在线| 国产成人精品电影久久久| 成人精品福利视频| 另类天堂视频在线观看| 国产成人精品国内自产拍免费看| 久久久久久久久久av| 亚洲欧洲xxxx| 国产日韩欧美日韩| 亚洲美女喷白浆| 亚洲大胆人体av| 日韩欧美精品网站| 欧美日本高清一区| 日韩视频第一页| 国产精品第一页在线| 日韩在线不卡视频| 国产精品av在线| 欧美一二三视频| 久久久免费电影| 国产精品美女www爽爽爽视频| www.久久草.com| 久久久亚洲影院| 青青草精品毛片| 国产成人精品午夜| 美女精品视频一区| 午夜精品久久久久久久久久久久久| 日本久久久久久久| 性色av一区二区三区免费| 欧美性xxxxx极品娇小| 日本欧美黄网站| 久久成人精品一区二区三区| 亚洲精品电影在线观看| 日韩成人免费视频| 久久免费在线观看| 国产成人激情视频| 欧洲s码亚洲m码精品一区| 日韩成人激情在线| 欧美精品一区在线播放| 久久久久久有精品国产| 日韩有码片在线观看| 国产精品白丝jk喷水视频一区| 欧美色另类天堂2015| 日韩中文字幕欧美| 国产一区红桃视频| 久久久国产视频91| 日韩免费观看在线观看| 欧美激情在线播放| 亚洲欧美日韩高清| 在线观看欧美www| 奇门遁甲1982国语版免费观看高清| 久久99亚洲热视| 亚洲国产精品福利| 亚洲国产成人久久综合一区| 国产噜噜噜噜噜久久久久久久久| 欧美日韩成人在线播放| 欧美日韩在线视频一区| 亚洲精品免费av| 4438全国亚洲精品在线观看视频| 精品久久久久久国产| 亚洲视频国产视频| 久久99亚洲热视| 欧美日韩亚洲网| 亚洲欧美激情精品一区二区| 国产精品美女免费看| 欧美体内谢she精2性欧美| 国产激情视频一区| 九九久久国产精品| 亚洲sss综合天堂久久| 国产精品久久久久久久9999| 久久久久久久久久国产精品| 久久九九亚洲综合| 亚洲女性裸体视频| 国产精品欧美日韩一区二区| 国产精品96久久久久久又黄又硬| 亚洲桃花岛网站| 97精品国产aⅴ7777| 久久精品亚洲国产| 国语自产偷拍精品视频偷| 久久久久国色av免费观看性色| 日韩av免费在线播放| 一区二区三区在线播放欧美| 大伊人狠狠躁夜夜躁av一区| 国产精品一区二区三区免费视频|