簡介
如今最常用的JavaScript庫之一是RequireJS。最近我參與的每個項目,都用到了RequireJS,或者是我向它們推薦了增加RequireJS。在這篇文章中,我將描述RequireJS是什麼,以及它的一些基礎場景。
異步模塊定義(AMD)
談起RequireJS,你無法繞過提及JavaScript模塊是什麼,以及AMD是什麼。
JavaScript模塊只是遵循SRP(Single Responsibility Principle單一職責原則)的代碼段,它暴露了一個公開的API。在現今JavaScript開發中,你可以在模塊中封裝許多功能,而且在大多數項目中,每個模塊都有其自己的文件。這使得JavaScript開發者日子有點難過,因為它們需要持續不斷的關注模塊之間的依賴性,按照一個特定的順序加載這些模塊,否則運行時將會放生錯誤。
當你要加載JavaScript模塊時,就會使用script標簽。為了加載依賴的模塊,你就要先加載被依賴的,之後再加載依賴的。使用script標簽時,你需要按照此特定順序安排它們的加載,而且腳本的加載是同步的。可以使用async和defer關鍵字使得加載異步,但可能因此在加載過程中丟失加載的順序。另一個選擇是將所有的腳本捆綁打包在一起,但在捆綁的時候你仍然需要把它們按照正確的順序排序。
AMD就是這樣一種對模塊的定義,使模塊和它的依賴可以被異步的加載,但又按照正確的順序。
CommonJS, 是對通用的JavaScript模式的標准化嘗試,它包含有 AMD 定義 ,我建議你在繼續本文之前先讀一下。在ECMAScript 6這個下一版本JavaScript 規范中,有關於輸出,輸入以及模塊的規范定義,這些將成為JavaScript語言的一部分,而且這不會太久。這也是關於RequireJS我們想說的東西。
RequireJS?
RequireJS是一個Javascript 文件和模塊框架,可以從 http://requirejs.org/下載,如果你使用Visual Studio也可以通過Nuget獲取。它支持浏覽器和像node.js之類的服務器環境。使用RequireJS,你可以順序讀取僅需要相關依賴模塊。
RequireJS所做的是,在你使用script標簽加載你所定義的依賴時,將這些依賴通過head.appendChild()函數來加載他們。當依賴加載以後,RequireJS計算出模塊定義的順序,並按正確的順序進行調用。這意味著你需要做的僅僅是使用一個“根”來讀取你需要的所有功能,然後剩下的事情只需要交給RequireJS就行了。為了正確的使用這些功能,你定義的所有模塊都需要使用RequireJS的API,否者它不會像期望的那樣工作。
RequireJS API 存在於RequireJS載入時創建的命名空間requirejs下。其主要API主要是下面三個函數:
在後面,我們將教你如果使用這些函數,但首先讓我們先了解下RequireJS的加載流程。
data-main屬性
當你下載RequireJS之後,你要做的第一件事情就是理解RequireJS是怎麼開始工作的。當RequireJS被加載的時候,它會使用data-main屬性去搜尋一個腳本文件(它應該是與使用src加載RequireJS是相同的腳本)。data-main需要給所有的腳本文件設置一個根路徑。根據這個根路徑,RequireJS將會去加載所有相關的模塊。下面的腳本是一個使用data-main例子:
<script src="scripts/require.js" data-main="scripts/app.js"></script>
另外一種方式定義根路勁是使用配置函數,後面我們將會看到。requireJs假設所有的依賴都是腳本,那麼當你聲明一個腳本依賴的時候你不需要使用.js後綴。
配置函數
如果你想改變RequireJS的默認配置來使用自己的配置,你可以使用require.configh函數。config函數需要傳入一個可選參數對象,這個可選參數對象包括了許多的配置參數選項。下面是一些你可以使用的配置:
下面是使用配置的一個例子:
require.config({ //By default load any module IDs from scripts/app baseUrl: 'scripts/app', //except, if the module ID starts with "lib" paths: { lib: '../lib' }, // load backbone as a shim shim: { 'backbone': { //The underscore script dependency should be loaded before loading backbone.js deps: ['underscore'], // use the global 'Backbone' as the module name. exports: 'Backbone' } } });
在這個例子中把根路徑設置為了scripts/app,由lib開始的每個模塊都被配置在scripts/lib文件夾下面,backbone 加載的是一個shim依賴。
用RequireJS定義模塊
模塊是進行了內部實現封裝、暴露接口和合理限制范圍的對象。ReuqireJS提供了define函數用於定義模塊。按章慣例每個Javascript文件只應該定義一個模塊。define函數接受一個依賴數組和一個包含模塊定義的函數。通常模塊定義函數會把前面的數組中的依賴模塊按順序做為參數接收。例如,下面是一個簡單的模塊定義:
define(["logger"], function(logger) { return { firstName: “John", lastName: “Black“, sayHello: function () { logger.log(‘hello'); } } } );
我們看,一個包含了logger的模塊依賴數組被傳給了define函數,該模塊後面會被調用。同樣我們看所定義的模塊中有一個名為logger的參數,它會被設置為logger模塊。每一個模塊都應該返回它的API.這個示例中我們有兩個屬性(firstName和lastName)和一個函數(sayHello)。然後,只要你後面定義的模塊通過ID來引用這個模塊,你就可以使用其暴露的API。
使用require函數
在RequireJS中另外一個非常有用的函數是require函數。require函數用於加載模塊依賴但並不會創建一個模塊。例如:下面就是使用require定義了能夠使用jQuery的一個函數。
require(['jquery'], function ($) { //jQuery was loaded and can be used now });
小結
在這篇文章中我介紹了RequireJS庫,它是我創建每個Javascript項目都會用到的庫函數之一。它不僅僅用於加載模塊依賴和相關的命令,RequireJS幫助我們寫出模塊化的JavaScript代碼,這非常有利於代碼的可擴展性和重用性。