Javascript文件加載:LABjs和RequireJS
傳統上,加載 Javascript 文件都是使用<script>標簽。
就像下面這樣:
<script type="text/javascript" src="example.js"></script>
<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 事件中指定的回調函數對它無效。
外部函數庫 LABjs 和 RequireJS,可以幫助我們更有效地管理 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 插件。