動態加載JS函數 JavaScript文件加載器LABjs API詳解

通常性的,當咱們須要加載js文件的時候都會使用script標籤來實現,相似於以下代碼:
javascript

代碼以下:

<script type="text/javascript" src="example.js"></script>


可是直接使用script標籤來加載js文件會有以下一些缺點:php

1.嚴格的讀取順序。因爲瀏覽器按照<script>在網頁中出現的順序,讀取Javascript文件,而後當即運行,致使在多個文件互相依賴的狀況下,依賴性最小的文件必須放在最前面,依賴性最大的文件必須放在最後面,不然代碼會報錯。html

2.性能問題。瀏覽器採用"同步模式"加載<script>標籤,也就是說,頁面會"堵塞"(blocking),等待javascript文件加載完成,而後再運行後面的HTML代碼。當存在多個<script>標籤時,瀏覽器沒法同時讀取,必須讀取完一個再去讀取另外一個,形成讀取時間大大延長,頁面響應緩慢。java

這個時候咱們就會想到去動態加載JS,動態加載js的實現方法相似於以下代碼jquery

代碼以下:

/*
*@desc:動態添加script
*@param src:加載的js文件的地址
*@param callback:js文件加載完成以後須要調用的回調函數
*@demo:
addDynamicStyle('http://webresource.c-ctrip.com/code/cquery/LABjs/LAB.js', function () {
    alert('攜程服務器上的lab.js加載完成')
});
*/
function addDynamicJS(src, callback) {
    var script = document.createElement("script");
    script.setAttribute("type", "text/javascript");
    script.src = src[i];
    script.charset = 'gb2312';
    document.body.appendChild(script);
    if (callback != undefined) {
        script.onload = function () {
            callback();
        }
    }
}

這樣不會形成頁面堵塞,但會形成另一個問題:這樣加載的Javascript文件,不在原始的DOM結構之中,所以在DOM-ready(DOMContentLoaded)事件和window.onload事件中指定的回調函數對它無效。git

這個時候咱們就會想到用一些外部函數庫來有效的管理JS加載問題。github

下面進入正題說說LAB.jsweb

LAB.jsajax

若是咱們使用傳統的方法來加載js的話,寫的代碼通常會以下方代碼所示風格。
bootstrap

代碼以下:

<script src="aaa.js"></script>
    <script src="bbb-a.js"></script>
    <script src="bbb-b.js"></script>
    <script type="text/javascript">
        initAaa();
        initBbb();
    </script>
    <script src="ccc.js"></script>
    <script type="text/javascript">
        initCcc();
    </script>

若是咱們使用LAB.js的話,要實現上述代碼功能,則使用以下方式

代碼以下:

<!--先加載lab.js庫-->
    <script src="http://webresource.c-ctrip.com/code/cquery/LABjs/LAB.js"></script>
    <script type="text/javascript">
        $LAB
        .script("aaa.js").wait()//不帶參數的.wait()方法表示當即運行剛纔加載的Javascript文件
        .script("bbb-a.js")
        .script("bbb-b.js")//依次加載aaa.js bbb-a.js bbb-b.js  而後執行initAaa initBbb
        .wait(function () {//帶參數的.wait()方法也是當即運行剛纔加載的Javascript文件,可是還運行參數中指定的函數。
            initAaa();
            initBbb();
        })
        .script("ccc.js")//再加載ccc.js 加載完成ccc.js以後執行initCcc方法
        .wait(function () {
            initCcc();
        });
    </script>

能夠同時運行多條$LAB鏈,可是它們之間是徹底獨立的,不存在次序關係。若是你要確保一個Javascript文件在另外一個文件以後運行,你只能把它們寫在同一個鏈操做之中。只有當某些腳本是徹底無關的時候,你才應該考慮把它們分紅不一樣的$LAB鏈,表示它們之間不存在相關關係。

通常性的使用示例

代碼以下:

$LAB
.script("script1.js") // script1, script2, and script3 相互不依賴, 能夠按照任意的順序執行
.script("script2.js")
.script("script3.js")
.wait(function(){
    alert("Scripts 1-3 are loaded!");
})
.script("script4.js") //必須等待script1.js,script2.js,script3.js執行完畢以後才能執行
.wait(function(){script4Func();});
代碼以下:

$LAB
.script("script.js")   
.script({ src: "script1.js", type: "text/javascript" })
.script(["script1.js", "script2.js", "script3.js"])
.script(function(){
    // assuming `_is_IE` defined by host page as true in IE and false in other browsers
    if (_is_IE) {
        return "ie.js"; // only if in IE, this script will be loaded
    }
    else {
        return null; // if not in IE, this script call will effectively be ignored
    }
})

在控制檯看LAB.js的加載信息

若是你想調試或者說在控制檯看各個js加載信息的話,可使用$LAB.setGlobalDefaults 方法,具體使用請看代碼示例。

代碼以下:

<!--先加載攜程的LAB庫  lab.js在網上也能夠下載-->
    <script type="text/javascript" src="http://webresource.c-ctrip.com/code/cquery/LABjs/LAB.js" charset="gb2312"></script>

    <script type="text/javascript">

        $LAB.setGlobalDefaults({ Debug: true }) //打開調試

        $LAB
            //第一個執行鏈
           .script('http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js')
           .script('http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js')

           //第二個執行鏈
           .wait(function () {
               //console.log(window.$)
               //console.log(window._)
           })

           //第三個執行鏈
           .script('http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/js/bootstrap.min.js')
           .script('http://cdnjs.cloudflare.com/ajax/libs/fancybox/2.1.5/jquery.fancybox.pack.js')

           //第四個執行鏈
           .wait(function () {
               // console.log(plugin1Function)
               // console.log(plugin2Function)
           })

           //第五個執行鏈
           .script('js/aaa.js')
           .script('js/bbb.js')

           //第六個執行鏈
           .wait(function () {
               // console.log(module1Function)
               // console.log(module2Function)
           })
    </script>

這個時候打開控制檯,看信息,以下圖所示:

 

實例

  //加載大的背景圖,不能等背景圖先顯示出來再執行html代碼

  <head>

  {insert_scripts files='LAB.min.js'}

  </head>

  <body>

  <script>

  $LAB.script("xxx/js/sign.min.js")

  .wait() //當即執行

  </script>

  </body>

 

  //除了背景圖還有輪換圖,目前只用到這兩種

  <html>

  <head>

  {insert_scripts files='LAB.min.js'}

  </head>

  <body>

  <script>

  $LAB.script("xxx/xxx/js/jquery.flexslider.min.js")

  .wait(function(){

  //banner 滾動

  $('#js_banner').flexslider({
                namespace:"",
                animation: "fade",
                selector: ".slides > li",
                pauseOnAction:false,
                controlNav:true,
                slideshowSpeed: 5000
            });    
    
            $('#whatsnew_pros').flexslider({
                namespace:"",
                animation: "slide",
                selector: ".slides > li",
                itemWidth: 150,
                pauseOnAction:false,
                controlNav:false,
                animationLoop: true,
                slideshow:false,  
                animationSpeed:50,
                minItems: 4,
                maxItems: 5
            });
            $('#seller_pros').flexslider({
                namespace:"",
                animation: "slide",
                selector: ".slides > li",
                itemWidth: 150,
                pauseOnAction:false,
                controlNav:false,
                animationLoop: true,
                slideshow:false,  
                animationSpeed: 50,
                minItems: 4,
                maxItems: 5
            });
            $('#specials_pros').flexslider({
                namespace:"",
                animation: "slide",
                selector: ".slides > li",
                itemWidth: 150,
                pauseOnAction:false,
                controlNav:false,
                animationLoop: true,
                slideshow:false,  
                animationSpeed: 50,
                minItems: 4,
                maxItems: 5
            });
            
            $("#seller_pros").hide();
            $("#specials_pros").hide();
            $("#whatsnew_pros").show();

  })

  </script>

  </body>
  </html>

JavaScript文件加載器LABjs API詳解

  在《高性能JavaScript》一書中提到了LABjs這個用來加載JavaScript文件的類庫,LABjs是Loading And Blocking JavaScript的縮寫,顧名思義,加載和阻塞JavaScript,而它的API script()和wait()則優雅地實現了這兩個功能,我在高性能JavaScript 加載和執行一文中也簡單講解了這兩個核心API的用法。固然,LABjs還有更多的API,本文用實例講解下LABjs其餘API。

$LAB.setGlobalDefaults() & $LAB.setOptions()

  二者所能設置的參數徹底一致,不一樣的是,前者是全局設置,做用在全部的$LAB鏈上;後者出如今某條鏈的開頭位置(後面接script()、wait()等),該設置只做用在這條鏈上。該參數能夠是一個包含多個鍵值對的對象

  • AlwaysPreserveOrder

  一個布爾值(默認false),若是設置爲true,則每一個script()後都會默認設置一個wait(),使得鏈上的腳本一個個執行。

複製代碼
$LAB
  .setOptions({AlwaysPreserveOrder:true}) // tells this chain to implicitly "wait" on // execution (not loading) between each script .script("script1.js") // script1, script2, script3, and script4 *DO* depend on each .script("script2.js") // other, and will execute serially in order after all 4 have have .script("script3.js") // loaded in parallel .script("script4.js") .wait(function(){script4Func();});
複製代碼
  • UseLocalXHR

  一個布爾值(默認true),若是是true的話,LABjs會用XHR Ajax去預加載同域的腳本文件。值得注意的是,只應用在老式的Webkit瀏覽器(那些既不能使用ordered-async也不能實現真正的預加載的瀏覽器),並且同域的狀況下,該設置才起效(否則直接無視)

  • CacheBust & AllowDuplicates

  LABjs對於緩存有一些奇怪的處理(關於緩存,能夠參考我前面的一篇文章瀏覽器緩存機制淺析),好比以下代碼:

$LAB.script('index.js');

  很簡單對吧?第一次載入,沒有任何問題,HTTP200從server端下載。可是f5後:

  (2015-8-3 這個問題有點詭異,有時HTTP304,有時HTTP200from cache 我也在github上詢問了做者 LABjs reads from cache when f5,回覆的大概意思是cache和labjs沒有任何關係,只和服務器和瀏覽器設置有關)

  竟然是從緩存讀取的!這就是說服務端的改動,對它不起效果!而一般狀況下f5後是會向服務器發送請求的,若是服務端文件沒有修改返回HTTP304讀取緩存,若是修改了文件直接load新的。針對這個問題咱們可使用CacheBust選項:

$LAB.setGlobalDefaults({CacheBust: true}) $LAB.script('index.js');

  這樣就能保證每次都從服務端讀取文件(從不讀取緩存)。

  還有一個問題,對於幾個相同的請求,LABjs默認只會執行一次:

$LAB.script('index.js').script('index.js');
$LAB.script('index.js');

  實際上index.js這個文件只執行了一次!若是index.js裏的代碼是打印hello world,也就是說只會被打印一次。如何作到能打印三次?用AllowDuplicates:

$LAB.setGlobalDefaults({AllowDuplicates: true}) $LAB.script('index.js').script('index.js'); $LAB.script('index.js');

  實際上上面的代碼,儘管會執行三次index.js,可是請求只有一次,其餘兩個都是緩存讀取,並且如前面所說,若是服務端修改了,也會從緩存讀取,這太可怕了。因此AllowDuplicates能夠配合CacheBust使用

$LAB.setGlobalDefaults({AllowDuplicates: true, CacheBust: true}) $LAB.script('index.js').script('index.js'); $LAB.script('index.js');

  其實就是帶了一串表明請求惟一的字符串,這在ajax請求中很常見。

  • BasePath

  一個字符串(默認空串),會將這個字符串加在每一個script()裏的URL的最前面。

  • Debug

  一個布爾值(默認false),若是開啓debug選項的話,會在控制檯打印信息,須要注意的是,只有使用了LAB-debug.min.js或者LAB.src.js該選項才work。

$LAB.script() & $LAB.wait()

  script()裏的參數能夠是不少形式,好比字符串(文件的相對路徑或者絕對路徑)、對象(src、type、charset src必須)、數組或者方法(或者前者們的組合),更多demo能夠參考Example 8 below。前三者很好理解,這裏簡單提下參數爲function的狀況,當script()裏的參數是個匿名的function的時候,該function會當即執行,它能夠return一個值,而該值必須是以上說的string、object或者array形式,至關於給該script()賦值了。

複製代碼
$LAB
  .script(function(){ // assuming `_is_IE` defined by host page as true in IE and false in other browsers if (_is_IE) { return "ie.js"; // only if in IE, this script will be loaded  } else { return null; // if not in IE, this script call will effectively be ignored  } }) .script("script1.js") .wait();
複製代碼

$LAB.queueScript() & $LAB.queueWait() & $LAB.runQueue() & $LAB.sandbox()

  script()和wait()會使得腳本當即執行(除非設置定時器),可是queueScript()和queueWait()能使得腳本在任意時刻執行,執行的時候帶上runQueue()就好了。

複製代碼
var a = $LAB.queueScript('index.js').queueWait(function() { console.log('hello world'); }); setTimeout(function() { a.runQueue() }, 1000);
複製代碼

  如上腳本就能在1000ms後執行,這樣的效果貌似script()配合定時器也能實現,可是在將來某一不肯定時刻執行就不行了(好比說一段指定代碼後)。若是有兩個鏈要在將來某時刻執行呢?

複製代碼
var a = $LAB.queueScript('index.js').queueWait(function() { console.log('hello world'); }); setTimeout(function() { a.runQueue() }, 1000); var b = $LAB.queueScript('index2.js').queueWait(function() { console.log('hello world'); }); setTimeout(function() { b.runQueue() }, 2000);
複製代碼

  如上代碼並沒能獲得預想的結果(實際上1000ms後一塊兒輸出),這時就須要用sandbox()建立一個新的實例。

複製代碼
var a = $LAB.queueScript('index.js').queueWait(function() { console.log('hello world'); }); setTimeout(function() { a.runQueue() }, 1000); var b = $LAB.sandbox().queueScript('index2.js').queueWait(function() { console.log('hello world'); }); setTimeout(function() { b.runQueue() }, 2000);
複製代碼

$LAB.noConflict() 

  使用noConflict()會將當前版本的LABjs回滾到舊的版本。(2015-08-04 這個解釋應該是錯的)

 

  read more from  LAB documentation

github LAB.js 2.0.3及如下版本版本https://github.com/getify/LABjs

       3.0目前正在進行重寫中https://github.com/getify/LABjs/tree/v3.0

參考自:https://www.jb51.net/article/61488.htm

    https://www.cnblogs.com/zichi/p/4689008.html

相關文章
相關標籤/搜索