在《高性能JavaScript》一書中提到了LABjs這個用來加載JavaScript文件的類庫,LABjs是Loading And Blocking JavaScript的縮寫,顧名思義,加載和阻塞JavaScript,而它的API script()和wait()則優雅地實現了這兩個功能,我在高性能JavaScript 加載和執行一文中也簡單講解了這兩個核心API的用法。當然,LABjs還有更多的API,本文用實例講解下LABjs其他API。
兩者所能設置的參數完全一致,不同的是,前者是全局設置,作用在所有的$LAB鏈上;後者出現在某條鏈的開頭位置(後面接script()、wait()等),該設置只作用在這條鏈上。該參數可以是一個包含多個鍵值對的對象。
一個布爾值(默認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();});
一個布爾值(默認true),如果是true的話,LABjs會用XHR Ajax去預加載同域的腳本文件。值得注意的是,只應用在老式的Webkit浏覽器(那些既不能使用ordered-async也不能實現真正的預加載的浏覽器),而且同域的情況下,該設置才起效(不然直接無視)
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請求中很常見。
一個字符串(默認空串),會將這個字符串加在每個script()裡的URL的最前面。
一個布爾值(默認false),如果開啟debug選項的話,會在控制台打印信息,需要注意的是,只有使用了LAB-debug.min.js或者LAB.src.js該選項才work。
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();
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);
使用noConflict()會將當前版本的LABjs回滾到舊的版本。(2015-08-04 這個解釋應該是錯的)
read more from LAB documentation