requireJS教程

使用 RequireJS 優化 Web 應用前端

基於 AMD(Asynchronous Module Definition)的 JavaScript 設計已經在目前較爲流行的前端框架中大行其道,jQuery、Dojo、MooTools、EmbedJS 等紛紛在其最新版本中加入了對 AMD 的支持。本文介紹的是另外一款較爲精簡的 RequireJS 框架,既想使用 AMD 的特性又不想引入一個龐大的庫的開發人員,不妨試試 RequireJS。RequireJS 能夠幫助用戶異步按需的加載 JavaScript 代碼,並解決 JavaScript 模塊間的依賴關係,提高了前端代碼的總體質量和性能。javascript

0 評論:html

施 偉, 高級軟件工程師, IBM前端

2012 年 9 月 10 日java

  • +內容jquery

在 IBM Bluemix 雲平臺上開發並部署您的下一個應用。web

如今就開始免費試用算法

AMD 簡介

前端開發在近一兩年發展的很是快,JavaScript 做爲主流的開發語言獲得了史無前例的熱捧。大量的前端框架出現了,這些框架都在嘗試着解決一些前端開發中的共性問題,可是實現又不盡相同。在這個背景下,CommonJS 社區誕生了,爲了讓前端框架發展的更加成熟,CommonJS 鼓勵開發人員一塊兒在社區裏爲一些完成特定功能的框架制定規範。AMD(Asynchronous Module Definition)就是其中的一個規範。數組

傳統 JavaScript 代碼的問題

讓咱們來看看通常狀況下 JavaScript 代碼是如何開發的:經過 <script> 標籤來載入 JavaScript 文件,用全局變量來區分不一樣的功能代碼,全局變量之間的依賴關係須要顯式的經過指定其加載順序來解決,發佈應用時要經過工具來壓縮全部的 JavaScript 代碼到一個文件。當 Web 項目變得很是龐大,前端模塊很是多的時候,手動管理這些全局變量間的依賴關係就變得很困難,這種作法顯得很是的低效。瀏覽器

AMD 的引入

AMD 提出了一種基於模塊的異步加載 JavaScript 代碼的機制,它推薦開發人員將 JavaScript 代碼封裝進一個個模塊,對全局對象的依賴變成了對其餘模塊的依賴,無須再聲明一大堆的全局變量。經過延遲和按需加載來解決各個模塊的依賴關係。模塊化的 JavaScript 代碼好處很明顯,各個功能組件的鬆耦合性能夠極大的提高代碼的複用性、可維護性。這種非阻塞式的併發式快速加載 JavaScript 代碼,使 Web 頁面上其餘不依賴 JavaScript 代碼的 UI 元素,如圖片、CSS 以及其餘 DOM 節點得以先加載完畢,Web 頁面加載速度更快,用戶也獲得更好的體驗。前端框架

CommonJS 的 AMD 規範中只定義了一個全局的方法,如清單 1 所示。

清單 1. AMD 規範
 define(id?, dependencies?, factory);

該方法用來定義一個 JavaScript 模塊,開發人員能夠用這個方法來將部分功能模塊封裝在這個 define 方法體內。

id 表示該模塊的標識,爲可選參數。

dependencies 是一個字符串 Array,表示該模塊依賴的其餘全部模塊標識,模塊依賴必須在真正執行具體的 factory 方法前解決,這些依賴對象加載執行之後的返回值,能夠以默認的順序做爲 factory 方法的參數。dependencies 也是可選參數,當用戶不提供該參數時,實現 AMD 的框架應提供默認值爲 [「require」,」exports」,「module」]。

factory 是一個用於執行改模塊的方法,它可使用前面 dependencies 裏聲明的其餘依賴模塊的返回值做爲參數,若該方法有返回值,當該模塊被其餘模塊依賴時,返回值就是該模塊的輸出。

CommonJS 在規範中並無詳細規定其餘的方法,一些主要的 AMD 框架如 RequireJS、curl、bdload 等都實現了 define 方法,同時各個框架都有本身的補充使得其 API 更實用。

回頁首

RequireJS 簡介

RequireJS 是一個很是小巧的 JavaScript 模塊載入框架,是 AMD 規範最好的實現者之一。最新版本的 RequireJS 壓縮後只有 14K,堪稱很是輕量。它還同時能夠和其餘的框架協同工做,使用 RequireJS 必將使您的前端代碼質量得以提高。

目前最新版本的 RequireJS 1.0.8 在 IE 6+、Firefox 2+、Safari 3.2+、Chrome 3+、Opera 10+ 上都工做的很好。

回頁首

實戰 RequireJS

在 Web 應用中使用 RequireJS

在 RequireJS 官方主頁上下載最新的版本的 require.js,放到 Web 頁面中。示例的 Web 項目結構圖 1 所示。

圖 1. Web 項目結構

圖 1. Web 項目結構

經過在 index.html 中加入一個 <script> 標籤直接引入 require.js 便可。

RequireJS 功能初探

RequireJS 使用起來很是的簡單,可是這些功能確是在 Web 前端開發中很是重要的,下面咱們來逐一看看如何使用 RequireJS 的各項功能。

使用 RequireJS 加載 JavaScript 文件

即便您的 Web 前端因爲種種歷史緣由尚未打算進行模塊化的設計,RequireJS 做爲 JavaScript 文件的加載器,仍是能夠幫助您來完成異步非阻塞的文件加載。

如清單 2 所示,有兩個 JavaScript 文件 a.js 和 b.js,裏面各自定義了 myFunctionA 和 myFunctionB 兩個方法,經過下面這個方式能夠用 RequireJS 來加載這兩個文件,在 function 部分的代碼能夠引用這兩個文件裏的方法。

清單 2. 加載 JavaScript 文件
 <script src="./js/require.js"></script> 
	 <script> 
    require(["./js/a.js", "./js/b.js"], function() { 
	    	 myFunctionA(); 
	    	 myFunctionB(); 
	    }); 
	 </script>

require 方法裏的這個字符串數組參數能夠容許不一樣的值,當字符串是以」.js」結尾,或者以」/」開頭,或者就是一個 URL 時,RequireJS 會認爲用戶是在直接加載一個 JavaScript 文件,不然,當字符串是相似」my/module」的時候,它會認爲這是一個模塊,而且會以用戶配置的 baseUrl 和 paths 來加載相應的模塊所在的 JavaScript 文件。配置的部分會在稍後詳細介紹。

這裏要指出的是,RequireJS 默認狀況下並無保證 myFunctionA 和 myFunctionB 必定是在頁面加載完成之後執行的,在有須要保證頁面加載之後執行腳本時,RequireJS 提供了一個獨立的 domReady 模塊,須要去 RequireJS 官方網站下載這個模塊,它並無包含在 RequireJS 中。有了 domReady 模塊,清單 2 的代碼稍作修改加上對 domReady 的依賴就能夠了。

清單 3. 頁面加載後執行 JavaScript
 <script src="./js/require.js"></script> 
	 <script> 
    require(["domReady!", "./js/a.js", "./js/b.js"], function() { 
	    	 myFunctionA(); 
	    	 myFunctionB(); 
	    }); 
	 </script>

執行清單 3 的代碼後,經過 Firebug 能夠看到 RequireJS 會在當前的頁面上插入爲 a.js 和 b.js 分別聲明瞭一個 <script> 標籤,用於異步方式下載 JavaScript 文件。async 屬性目前絕大部分瀏覽器已經支持,它代表了這個 <script> 標籤中的 js 文件不會阻塞其餘頁面內容的下載。

清單 4. RequireJS 插入的 <script>
 <script type="text/javascript" charset="utf-8" async="" data-requirecontext="_" 
 data-requiremodule="js/a.js" src="js/a.js"></script>

使用 RequireJS 來定義 JavaScript 模塊

這裏的 JavaScript 模塊與傳統的 JavaScript 代碼不同的地方在於它無須訪問全局的變量。模塊化的設計使得 JavaScript 代碼在須要訪問」全局變量」的時候,均可以經過依賴關係,把這些」全局變量」做爲參數傳遞到模塊的實現體裏,在實現中就避免了訪問或者聲明全局的變量或者函數,有效的避免大量並且複雜的命名空間管理。

如同 CommonJS 的 AMD 規範所述,定義 JavaScript 模塊是經過 define 方法來實現的。

下面咱們先來看一個簡單的例子,這個例子經過定義一個 student 模塊和一個 class 模塊,在主程序中實現建立 student 對象並將 student 對象放到 class 中去。

清單 5. student 模塊,student.js
 define(function(){ 
	 return { 
	    createStudent: function(name, gender){ 
	    	 return { 
	    		 name: name, 
	    		 gender: gender 
	    	 }; 
	    } 
	 }; 
 });
清單 6. class 模塊,class.js
 define(function() { 
 var allStudents = []; 
        return { 
            classID: "001", 
            department: "computer", 
            addToClass: function(student) { 
            allStudents.push(student); 
            }, 
            getClassSize: function() { 
            return allStudents.length; 
            } 
        }; 
     } 
 );
清單 7. 主程序
 require(["js/student", "js/class"], function(student, clz) { 
 clz.addToClass(student.createStudent("Jack", "male")); 
 clz.addToClass(student.createStudent("Rose", "female")); 
 console.log(clz.getClassSize());  // 輸出 2 
 });

student 模塊和 class 模塊都是獨立的模塊,下面咱們再定義一個新的模塊,這個模塊依賴 student 和 class 模塊,這樣主程序部分的邏輯也能夠包裝進去了。

清單 8. 依賴 student 和 class 模塊的 manager 模塊,manager.js
 define(["js/student", "js/class"], function(student, clz){ 
 return { 
    addNewStudent: function(name, gender){ 
    clz.addToClass(student.createStudent(name, gender)); 
	    }, 
    getMyClassSize: function(){ 
    return clz.getClassSize(); 
    } 
	 }; 
 });
清單 9. 新的主程序
 require(["js/manager"], function(manager) { 
 manager.addNewStudent("Jack", "male"); 
 manager.addNewStudent("Rose", "female"); 
 console.log(manager.getMyClassSize());// 輸出 2 
 });

經過上面的代碼示例,咱們已經清楚的瞭解瞭如何寫一個模塊,這個模塊如何被使用,模塊間的依賴關係如何定義。仍是有一些使用技巧須要提示一下:

  • 儘可能不要提供模塊的 ID,如 AMD 規範所述,這個 ID 是可選項,若是提供了,在 RequireJS 的實現中會影響模塊的可遷移性,文件位置變化會致使須要手動修改該 ID。

  • 每一個 JavaScript 文件只定義一個模塊,模塊名稱和文件路徑的查找算法決定了這種方式是最優的,多個的模塊和文件會被優化器進行優化。

  • 避免模塊的循環依賴,若是實在避免不了,能夠模塊中加上對」require」模塊的依賴,在代碼中直接用 require(」dependencyModuleName」)。

配置 RequireJS

前面的介紹中,咱們彷佛忽略了一個基本問題,模塊名字是怎麼來的?當我在 require 一個模塊時,這個模塊是如何映射到具體的 JavaScript 文件上去?這就涉及到如何配置 RequireJS。

最簡化的加載 RequireJS 的方式如清單 2 所示,在這種狀況下,咱們沒有指定一個 baseUrl 和 paths 給 RequireJS,若是經過如清單 10 所示方式,則 data-main 指定了一個在當前 index.html 目錄並行的文件夾下的 /js/main.js 做爲程序入口,而 /js 目錄也將做爲 baseUrl 在其餘模塊定義時候使用。

清單 10. 載入 require.js
 <script data-main="js/main" src="scripts/require.js"></script>

所以,咱們前面示例中的全部模塊依賴,均可以去掉」js/」,直接寫 」student」, 」class」,」manager」 等。

一種更爲直接的方式顯示指定 baseUrl 和 paths 就是利用 require.config 來設置這些參數。如清單 11 所示。

清單 11. 配置 RequireJS
 <script type="text/javascript" src="./js/require.js"></script> 
 <script type="text/javascript"> 
  require.config({ 
    baseUrl: "./js", 
    paths: { 
        "some": "some/v1"
    }, 
 waitSeconds: 10 
 }); 
  require( ["some/module", "my/module", "./js/a.js"], 
    function(someModule,    myModule) {} 
  ); 
 </script>

baseUrl指明的是全部模塊的 base URL,好比」my/module」所加載的 script實際上就是 /js/my/module.js。注意,以 .js 結尾的文件加載時不會使用該 baseUrl,它們仍然會使用當前 index.html所在的相對路徑來加載,因此仍然要加上」./js/」。若是 baseUrl沒有指定,那麼就會使用 data-main中指定的路徑。

paths 中定義的路徑是用於替換模塊中的路徑,如上例中的 some/module 具體的 JavaScript 文件路徑是 /js/some/v1/module.js 。

waitSeconds 是指定最多花多長等待時間來加載一個 JavaScript 文件,用戶不指定的狀況下默認爲 7 秒。

另一個重要的配置是 packages,它能夠指定其餘符合 CommonJS AMD 規範的目錄結構,由此帶來了豐富的擴展性。如 Dojo、jQuery 等的模塊也能夠經過該配置來讓 RequireJS 加載。

其餘可配置的選項還包括 locale、context、deps、callback等,有興趣的讀者能夠在 RequireJS 的官方網站查閱相關文檔。

回頁首

綜合運用 RequireJS

當 RequireJS 與其餘框架一塊兒工做的時候,顯然它是能夠做爲統一的加載器來加載其餘框架。鑑於 jQuery、Dojo 等已經支持了 AMD ,那麼就有可能在定義本身的模塊的時候,經過適當配置,直接把其餘框架的模塊做爲依賴對象。

RequireJS 和 Dojo

清單 11是一個基本的 RequireJS 和 Dojo 集成配置方法,這裏關鍵是將 dojo 和 dijit 都在 packages 裏面註冊一下。

清單 12. 配置 RequireJS 和 Dojo
 <script> 
 require = { 
 packages: [ 
 { 
 name: 「dojo」, 
 location: 「dojo」, 
 main:」lib/main-browser」, 
 lib: 「.」
 }, 
 { 
 name: 「dijit」, 
 location: 「dijit」, 
 main:」lib/main」, 
 lib: 「.」
 } 
 ], 
 paths: { 
 require: 「./js」
 }, 
 ready: function () { 
 require([「my/module」], function (module) { 
 }); 
 } 
 }; 
 </script>

在定義 module 這個模塊時就能夠直接將 dojo 和 dijit 裏的模塊做爲依賴對象了。

RequireJS 和 jQuery

把 jQuery 做爲一個依賴模塊來使用也很是簡單,只須要在 RequireJS 裏的 config 裏作相應的配置就能夠了。

清單 13. 配置 RequireJS 和 jQuery
 require.config({ 
 paths: { 
"jquery": "./js/jquery-1.7"
 } 
 }); 
 require(["jquery"],function(jQ){ 
 console.log(jQ); 
 });

RequireJS 和 Web Workers

Web Workers 是多線程的 JavaScript,每一個 worker 裏面的腳本都 會啓動一個新的線程來執行,經過在 worker 裏面用 importsScript 來加載 require.js 能夠直接在 worker 裏面使用 RequireJS 。

清單 14. RequireJS 和 Web Workers
 importScripts('./js/require.js'); 
 require(["require"], 
    function(require) { 
        postMessage("test"); 
    } 
 );

回頁首

小結

本文簡單介紹了 AMD 的概念和它帶來的好處,深刻介紹瞭如何使用 RequireJS 來定義本身的 JavaScript 模塊,管理這些模塊的依賴關係,異步按需加載這些模塊。並進一步討論瞭如何用 RequireJS 和其餘框架協同工做,有興趣的讀者能夠繼續閱讀相關文檔瞭解更多詳細的用法。

相關文章
相關標籤/搜索