首頁 >web前端 >js教程 >詳談LABJS按需動態載入js檔案_javascript技巧

詳談LABJS按需動態載入js檔案_javascript技巧

WBOY
WBOY原創
2016-05-16 16:00:271684瀏覽

LABjs 是一個很小的JavaScript 工具,用來根據需要載入JavaScript 文件,透過使用該工具可以提升頁面的效能,避免載入不需使用的JavaScript 文件,可以實現動態並行載入腳本文件,以及管理載入腳本檔案的執行順序。

簡單範例

$LAB
.script("script1.js", "script2.js", "script3.js")
.block(function(){
  // wait for all to load, then do something
  script1Func();
  script2Func();
  script3Func();
});

介紹下LABJS的幾個例子:
實例1:

$LAB
  .script("script1.js")
  .script("script2.js")
  .script("script3.js")
  .wait(function(){ // 等待所有script加载完再执行这个代码块
    script1Func();
    script2Func();
    script3Func();
  });

實例2:

$LAB 
  .script({ src: "script1.js", type: "text/javascript" })
  .script("script2.js")
  .script("script3.js")
  .wait(function(){ // 等待所有script加载完再执行这个代码块
    script1Func();
    script2Func();
    script3Func();
  });

實例3:

$LAB
  .script("script1.js", "script2.js", "script3.js")
  .wait(function(){ // 等待所有script加载完再执行这个代码块
    script1Func();
    script2Func();
    script3Func();
  });

實例4:

$LAB
  .script( [ "script1.js", "script2.js" ], "script3.js")
  .wait(function(){ // 等待所有script加载完再执行这个代码块
    script1Func();
    script2Func();
    script3Func();
  });

實例5:

$LAB
  .script("script1.js").wait() // 空的wait()只是确保script1在其他代码之前被执行
  .script("script2.js") // script2 和 script3 依赖于 script1
  .script("script3.js").wait() // 但是script2 和 script3 并不互相依赖,可以并行下载
  .script("script4.js") // script4 依赖于 script1, script2 及 script3
  .wait(function(){script4Func();});

實例6:

$LAB
  .script("script1.js") // script1, script2, and script3 之间没有依赖关系,
  .script("script2.js") // 所以可以任意顺序执行
  .script("script3.js")
  .wait(function(){ // 如果需要,这里当然可以执行javascript函数
    alert("Scripts 1-3 are loaded!");
  })
  .script("script4.js") // 依赖于 script1, script2 及 script3
  .wait(function(){script4Func();});

實例7:

$LAB
  .setOptions({AlwaysPreserveOrder:true}) // 设置每个脚本之间等待
  .script("script1.js") // script1, script2, script3, script4 互相依赖
  .script("script2.js") // 并且并行下载后循序执行
  .script("script3.js")
  .script("script4.js")
  .wait(function(){script4Func();});

實例8:

$LAB
  .script(function(){
    // `_is_IE`的值ie为true ,非ie为false
    if (_is_IE) {
      return "ie.js"; // 如果是ie则这个js会被加载
    }
    else {
      return null; //如果不是ie这个代码就会被略过
    }
  })
  .script("script1.js")
  .wait();

LABjs載入方式

LABjs裡的動態載入腳本文件,是指頁面的js腳本執行時,透過多種方法去載入外部的js(主要區別於html頁面裡,透過<script>標籤靜態載入的腳本)<br /> </script>

動態載入腳本的方式有很多,優缺點不一,此處不贅述,有興趣的童鞋可以參見本文末尾的參考連結 :)。

LABjs裡主要使用了三種技巧,分別為Script Element、XHR Injection以及Cache Trick

先對這三種載入方式進行簡單介紹,第四部分再分析LABjs源碼實作裡面對著三種方式分別的使用場景

Script Element(LABjs預設為載入方式)

最常見的腳本動態載入方式,優點很多,包括:1、實作簡單 2、可跨域 3、不會阻塞其他資源的載入 等

Opera/Firefox(舊版)下:腳本執行的順序與節點被插入頁面的順序一致

IE/Safari/Chrome下:執行順序無法保證

注意:

新版本的Firefox下,腳本執行的順序與插入頁面的順序不一定一致,但可透過將script標籤的async屬性設為false來保證順序執行

舊版的Chrome下,腳本執行的順序與插入頁面的順序不一定一致,但可透過將script標籤的async屬性設為false來保證順序執行

XHR Injection
透過ajax請求載入腳本文件,然後再透過以下方式執行:
eval:常見方式
XHR injection:建立一個script元素,並將請載入的腳本檔案的內容注入
主要限制:無法跨域
Cache Trick(強烈依賴瀏覽器的特性實現,不建議使用)
當你將script元素的type屬性設定為瀏覽器不認識的值,例如”text/cache”、”text/casper”、”text/hellworld”等,不同瀏覽器的行為如下:
IE/Safari/Chrome(舊版)裡:腳本照常加載,但不會執行,假設瀏覽器沒有禁用緩存,加載後的腳本會被瀏覽器緩存起來,當需要用到的時候,只需要重新創建個script標籤,將type設為正確的值,src指向先前請求的檔案url即可(相當於從快取裡讀取檔案)
Opera/Firefox:不載入
備註:
強依賴瀏覽器的特性實現,有可能隨著瀏覽器特性實現的改變而失效,不建議使用
新版的chrome瀏覽器,將script元素的type設為非”text/javascript”,不會再對腳本檔案進行載入。

LABjs裡關於腳本載入採用方案的判斷

忽略技術細節,透過一段偽代碼來描述LABjs裡面的實現,大致為:
首先判斷是否對請求的腳本進行預先載入(是否進行預先載入的判斷條件看偽程式碼註解);
如進行預加載,再判斷瀏覽器是否支援真正的預加載;如支援真正的預加載,則預加載之;如否,判斷請求的腳本是否跟當前頁面同域,如實,採用XHR Injection,如否,採用Cache Trick;
如不進行預先加載,判斷瀏覽器支不支援script元素的async屬性(請參閱偽代碼註釋),如是,設定async屬性,並請求腳本檔案;如否,直接透過script元素載入腳本檔案;
 

if(ifPreloadScript){  //当请求的脚本文件是否进行预加载:1、需要预加载 2、浏览器支持预加载
  if(supportRealPreloading){  //如果支持真正的预加载
    if(supportPreloadPropNatively){  //支持通过设置script标签的preload属性,实现script的预加载,以及分离加载和执行
                    //Nicholas C. Zakas大神的美好愿望,尚未有浏览器支持:/blog/2011/02/14/separating-javascript-download-and-execution/
      script.onpreload = callback;
      script.newPreload = true;
      script.src = targetUrl;
    }else{
      script.onreadystatechange = callback;  //其实就是指IE浏览器,假设指定了script元素的src属性,IE浏览器里会立即加载
      script.src = targetUrl;  //即使script元素没有被插入页面,callback为预加载后的回调
    }
  }
  else if(inSameDomain){  //非跨域,采用XHR Injection:请求的脚本与当前页面处于同一个域
    xhr = new XMLHttpRequest();  //由于上个判断已经将IE无情地抛弃在这个条件分支之外,所以大胆地用 new XMLHttpRequest()吧
    xhr.onreadystatechange = callback;
    xhr.open("GET",targetUrl);
    xhr.send();
  }
  else{  //最无奈的后招,Cache Trick,新版chromei已经不支持
    script.onload = callback;
    script.type = 'text/cache';  
    script.src = targetUrl;
  }
}else{
  if(canContrlExecutionOrderByAsync){  //如果能够通过script元素的async属性来强制并行加载的脚本顺序执行
                    //kyle大神着力推进的提案,目前已被html5小组接受并放入草案:/Dynamic_Script_Execution_Order#My_Solution
    script.onload = callback;
    script.async = false;  //将script元素的async设为false,可以保证script的执行顺序与请求顺序保持一致
    script.src = targetUrl;
  }
  else{
    script.onload = callback;
    script.src = targetUrl;  
  }
}

實際上,當你在頁面創建一個img節點,並將其src指向一個腳本文件,在部分瀏覽器裡同樣能夠起到文件預加載的作用,那麼LABjs的作者是不是沒有想到這一點呢?

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn