Javascript檔案載入:LABjs和RequireJS

阮一峰發表於2011-10-03

傳統上,載入Javascript檔案都是使用<script>標籤。

就像下面這樣:

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

Javascript檔案載入:LABjs和RequireJS

<script>標籤很方便,只要加入網頁,瀏覽器就會讀取並執行。但是,它存在一些嚴重的缺陷。

  (1)嚴格的讀取順序。由於瀏覽器按照<script>在網頁中出現的順序,讀取Javascript檔案,然後立即執行,導致在多個檔案互相依賴的情況下,依賴性最小的檔案必須放在最前面,依賴性最大的檔案必須放在最後面,否則程式碼會報錯。

  (2)效能問題。瀏覽器採用"同步模式"載入<script>標籤,也就是說,頁面會"堵塞"(blocking),等待javascript檔案載入完成,然後再執行後面的HTML程式碼。當存在多個<script>標籤時,瀏覽器無法同時讀取,必須讀取完一個再去讀取另一個,造成讀取時間大大延長,頁面響應緩慢。

為了解決這些問題,可以使用DOM方法,動態載入Javascript檔案。

  function loadScript(url){

    var script = document.createElement("script");

    script.type = "text/javascript";

    script.src = url;

    document.body.appendChild(script);

  }

這樣做的原理是,瀏覽器即時創造出一個<script>標籤,然後"非同步"讀取Javascript檔案。這樣不會造成頁面堵塞,但會造成另外一個問題:這樣載入的Javascript檔案,不在原始的DOM結構之中,因此在DOM-ready(DOMContentLoaded)事件和window.onload事件中指定的回撥函式對它無效。

外部函式庫LABjsRequireJS,可以幫助我們更有效地管理Javascript載入。

下面根據ScriptJunkie的文章,舉一個最簡單的例子,來說明這兩個函式庫的基本用法。更高階的用法,請參閱它們的文件。

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

  <script src="script2-a.js"></script>

  <script src="script2-b.js"></script>

  <script type="text/javascript">

    initScript1();

    initScript2();

  </script>

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

  <script type="text/javascript">

    initScript3();

  </script>

上面這段程式碼,將依次載入4個javascript檔案:script1.js、script2-a.js、script2-b.js和script3.js。在載入完前三個檔案後,執行兩個函式initScript1()和initScript2();載入完第四個檔案後,再執行函式initScript3()。

下面,用LABjs對其進行改寫:

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

  <script type="text/javascript">

    $LAB

     .script("script1.js").wait()

     .script("script2-a.js")

     .script("script2-b.js")

     .wait(function(){

       initScript1();

       initScript2();

     })

     .script("script3.js")

     .wait(function(){

       initScript3();

     });

  </script>

首先,$LAB物件替代了<script>標籤,然後.script()方法表示載入Javascript檔案,不帶引數的.wait()方法表示立即執行剛才載入的Javascript檔案,帶引數的.wait()方法也是立即執行剛才載入的Javascript檔案,但是還執行引數中指定的函式。

這裡需要注意的是,可以同時執行多條$LAB鏈,但是它們之間是完全獨立的,不存在次序關係。如果你要確保一個Javascript檔案在另一個檔案之後執行,你只能把它們寫在同一個鏈操作之中。只有當某些指令碼是完全無關的時候,你才應該考慮把它們分成不同的$LAB鏈,表示它們之間不存在相關關係。

接下來是requireJS的改寫:

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

  <script type="text/javascript">

    require([

      "script1.js",
      "script2-a.js",
      "script2-b.js",
      "script3.js"

     ],

     function(){

      initScript1();
      initScript2();
      initScript3();

     }

    );

  </script>

require()接受兩個引數,第一個陣列表示所要載入的Javascript檔案,第二個是載入完成後所要執行的回撥函式。原生的require()不支援按次序載入,所以四個Javascript檔案到底先載入哪個,無法事前知道,require()只保證這四個檔案全部載入完成之後,才會執行所指定的回撥函式。

如果按次序載入對你很重要,你可以使用官方提供的order外掛

(完)

相關文章