require.js入門教程

ZN_WEB發表於2016-05-04

說明:本文只提供快速入門內容,方便快速進入實戰狀態。更高階的配置,請參考官網文件。

當初之所以使用 RequireJS 等工具,是因為想提高js的載入速度,避免不必要的堵塞。但通過一段時間的使用,發現 RequireJS 更重要的作用是作為名稱空間使用。

一、基本用法

RequireJS 官網文章不是中文的,篇幅不少(官方網址:http://requirejs.org)。網上的其他相關文章,有的講的也很複雜。

其實,RequireJS 極其簡單。如果你對 c# 或 Java 語言的名稱空間有一點點了解,那麼,RequireJS 的用法和作用,可以用 c# 中的兩行程式碼來類比說明:

1 using xx=wojilu.Core;
2 namespace MyApp {
3     public class MyClass {
4         public void MyTest() {}
5     }
6 }

RequireJS主要的功能,就是實現c#程式碼的第一行和第二行的功能:1)引入需要使用的名稱空間(順便加個別名也行);2)將自己的程式碼放到名稱空間中,避免全域性汙染。

因為 JavaScript 天生的缺點,語言本身沒有整合名稱空間的概念,所以變數名、函式名很容易發生衝突。這些年,大家想盡了各種辦法,給 js 新增名稱空間的概念,其中最成熟的套路,就是 RequireJS 這種。

我們可以看到,在c#中只要兩行程式碼的事情,在 js 中,得用多麼複雜的類庫,比如 RequireJS 去解決。

下面我們看一下 RequireJS 的具體寫法,新建一個獨立的 wojilu.test1.js 檔案,然後輸入如下程式碼:

1 define( ['wojilu.Core'], function(xx) {
2     return {
3         MyTest : function() { alert( 'wojilu1 module' );}
4     };
5 });

和上面的c#程式碼對比一下,RequireJS 同樣也做了兩件事情:
1、引入名稱空間 wojilu.Core,同時給它取了一個別名 xx;
2、將自己的所有程式碼放在 define 中,避免全域性化的汙染衝突。

總之,RequireJS 定義了(define)一個名稱空間,在定義的時候,順便引用了需要使用其他名稱空間。我們注意到,按照 RequireJS 的術語,它把名稱空間叫做“模組”。注意,在這裡,RequireJS 定義的模組(名稱空間)是匿名的,沒有取名,這是和c#不同的地方。

但這個不要緊,因為其他 js 在用到你這個 js 的時候,一般是根據檔名稱載入的,同時可以通過上面的 xx 這種方式,給模組(名稱空間)自定義別名,所以,取不取名,還真不是關鍵。

我們新建另外一個 wojilu.test2.js 檔案,來使用 wojilu.test1.js:

1 define( ['wojilu.test1'], function( t1 ) {
2     return {
3         NewTest : function() { t1.MyTest();}
4     };
5 });

同樣,也是通過檔名(不需要字尾名),引入了 wojilu.test1 名稱空間,並給它取了別名 t1,然後在程式碼中使用 t1.MyTest() 方法。

按照 RequireJS 的規範,所有的模組定義,都必須放在 return {} 物件中。也就是說,你的程式碼都要寫在 return 返回的 {} 物件裡面。這會不會導致程式碼臃腫難看?當然不會。你可以重構一下,比如這樣做:

01 define( ['wojilu.test1'], function( t1 ) {
02  
03     function someFunc1() {
04         // 實際主要程式碼
05     }
06  
07     function someFunc2() {
08         // 實際主要程式碼
09     }
10     // 通過 return 方式,將需要公開的函式暴露出來,供其他 js 呼叫
11     return {
12         NewTest : function() { t1.MyTest();},
13         fun1 : someFunc1,
14         fun2 : someFunc2
15     };
16 });

當然,要使用 RequireJS 的這些功能,你必須在頁面中引用 require.js 檔案

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

二、其他用法

上面的用法是標準用法,但 RequireJS 在載入其他 “模組/名稱空間/js檔案” 的時候,內部是通過傳統的 <script src="some.js"></script> 來實現的,所以,你也可以把 RequireJS 僅僅當做 js 載入器使用。比如這行程式碼:

1 <script src="some.js"></script>

可以寫成:

1 <script>require( ["some" ] );</script>

雖然僅僅是寫法的變化,但帶來了很多好處:
1、避免阻塞,提高了 js 的載入效能;
2、通過程式設計使用 require 方法載入,而不是<script>硬寫,更加靈活。

三、基本配置

上面使用 RequireJS 的方式是這樣處理的:

1 <script src="require.js"></script>
這種寫法雖然簡單,但其實並不推薦,一般的寫法還要再加個屬性:

1 <script data-main="js/main" src="js/require-jquery.js"></script>
就像一個c程式總有一個 main 方法作為入口一樣,上面這種寫法,做了幾件事情:
1、載入了 require-jquery.js 檔案。注意,官方提供了 RequireJS 和 jquery 的打包版本,推薦。
2、在載入之後,載入入口檔案 js/main.js ,注意,main.js 寫進去的時候,不需要字尾名。

你的所有其他 js 模組檔案,都可以寫在 main.js 裡面,通過 main.js 載入。

四、載入的用法

到此為止,我們遇到了兩個關鍵詞,一個是 define ,可以用來定義模組(名稱空間),第一部分我們講了;還有一個是 require,可以直接載入其他 js。它除了簡單的用法:

1 <script>
2 require( ["some" ] );
3 </script>

之外,還有和 define 類似的複雜用法:

1 <script> 
2 require(["aModule""bModule"], function() { 
3     myFunctionA(); // 使用 aModule.js 中的函式 myFunctionA
4     myFunctionB(); // 使用 bModule.js 中的函式 myFunctionB
5 }); 
6 </script> 

總結一下,define 是你定義自己的模組的時候使用,可以順便載入其他js;require 直截了當,供你載入用的,它就是一個載入方法,載入的時候,可以定義別名。

五、在 RequireJS 之前執行

有了 RequireJS 這個工具,我們可以將網頁 <head> 中的所有 js 都挪到頁尾,以提高 js 的載入速度。請在 www.wojilu.com 網頁上右鍵檢視 html 原始碼,看一下實際效果。

理論上,js 指令碼都應該放到獨立的 js 檔案中,而不是直接嵌入網頁內聯執行,好處是方便瀏覽器快取,不用每次都載入頁面內容。但只要你不是有真正的程式碼潔癖,總有一些特殊時候,需要在載入 require.js 之前,執行一些script指令碼。這時候,你可以使用 wojilu 目前的做法,把所有的程式碼都放在一個叫 _run 的函式中,比如在 require.js 載入程式碼上面一行:

1 <script>
2     _run(function () {
3         require(['wojilu.core.base'], function (x) { x.customSkin().backTop(); });
4     });
5 </script>

這行程式碼引用了 wojilu.core.base 檔案,但因為是放在 _run 中的,所以並不是立刻執行,而是延遲到 require.js 載入之後執行。 run 表示執行,前面加上下劃線,表示“延遲”執行。

至於wojilu如何做到這一點的,請自己閱讀原始碼,其實思路是很簡單的。

六、版本號

為了在js更新之後,及時通知客戶端重新整理快取,我們一般需要給js加上版本號,具體說明,參看這裡:http://www.wojilu.com/Common/Page/13 。在 RequireJS 中也可以給所有需要載入的 js 加上版本號,方法是給 require.js 提供一個配置檔案。請在 requrie.js 載入之前,提供一個全域性變數 require:

1 <script>
2     var require = {
3          urlArgs: 'v=版本號'
4     };
5 </script>
6 <script src="scripts/require.js"></script>

注意:不要把 require 變數寫成 window.require ,據說在IE下會有問題。

RequireJS 還提供了其他豐富的配置選項,具體請訪問官網檢視。

七、其他問題

1、路徑與字尾名

在 require 一個 js 檔案的時候,一般不需要加上字尾名。如果加上字尾名,會按照絕對路徑載入。沒有字尾名,是按照下面的路徑載入:

1 <script data-main="js/main" src="js/require-jquery.js"></script>

也就是預設載入 data-main 指定的目錄,即 js/main.js 檔案所在的目錄。當然,你可以通過配置檔案修改。

2、define 定義模組方法只能用在獨立的js檔案中,不能在頁面中直接使用。
否則會報 Mismatched anonymous define() module 錯誤。

3、和其他第三方js類庫是否衝突?

不會衝突。一般比較規範的類庫,都會給自己的js加上名稱空間。比如 wojilu 舊有的 wojilu.common.js ,其實就是放在 wojilu 名稱空間中(當然是通過更原始的方式實現名稱空間的)。

在通過 RequireJS 載入這些第三方的 js 的時候,完全不要有任何擔憂。

當然,如果第三方類庫能夠使用 RequireJS 的方式進行改造,那是最好。比如 wojilu 中大多數js 都按照 RequireJS 的方式進行了改造。但是,如果你不改造,也是完全不要緊的。

4、在程式碼中 require 一個檔案多次,是否會導致瀏覽器反覆載入?

不會,這是 RequrieJS 的優點,即使你反覆 require 它,它只載入一次。

轉載自:http://www.wojilu.com/Forum1/Topic/4205