javascript
AMD规范:简单而优雅的动态载入JavaScript代码
本文翻譯自http://www.sitepen.com/blog/2010/11/04/requirejsamd-module-forms/,并加入部分自己的解釋。
CommonJS 提出了一種用于同步或異步動態(tài)加載JavaScript代碼的API規(guī)范,非常簡單卻很優(yōu)雅,稱之為AMD(Modules/AsynchronousDefinition)。RequireJS和NodeJS的Nodules已經(jīng)實現(xiàn)了這個API,而Dojo也將馬上完全支持(Dojo1.6)。規(guī)范本身非常簡單,甚至只包含了一個API:?
define([module-name?], [array-of-dependencies?], [module-factory-or-object]);
通過參數(shù)的排列組合,這個簡單的API可以從容應(yīng)對各種各樣的應(yīng)用場景,如下所述。
?
匿名模塊
在這種場景下,無需輸入模塊名,即省略第一個參數(shù),僅包含后兩個參數(shù):依賴模塊的列表以及回調(diào)函數(shù),例如一個簡單的匿名模塊可以用如下代碼定義:
define(["math"], function(math){?
? return {?
??? addTen: function(x){?
????? return math.add(x, 10);?
??? }?
? };?
});?
在這里,第一個參數(shù)表示依賴的模塊列表,即math模塊。一旦所有依賴的模塊被載入完成,那么第三個參數(shù)定義的回調(diào)函數(shù)將被執(zhí)行,依賴模塊的引用作為參數(shù)傳遞給回調(diào)函數(shù)。
如例子中所示,如果模塊名被省略不寫,那么這是一個匿名模塊。通過這種強大的方式,模塊的源代碼與它的標(biāo)識可以做到不相關(guān)。從而可以在不改變模塊代碼的情況下移動源碼文件的位置。這個技術(shù)遵循了基本的DRY(Don't Repeat Yourself)原則,避免了模塊標(biāo)識的多次存儲(文件名/路徑信息不會在代碼中重復(fù))。這不僅使得模塊的開發(fā)變得更加容易,而且為模塊的重用提供了極大的靈活性。
下面我們看如何從一個Web頁面載入這個模塊。我們假設(shè)上面的模塊存儲在文件adder.js中。使用RequireJS,我們可以用下面方式來載入這個模塊:?
<script src="require.js"></script>?
<script>?
require(["adder"], function(adder){?
? // ready to use adder?
});?
</script>??
一旦代碼被執(zhí)行,RequireJS將會自動去調(diào)用adder模塊所有的依賴模塊。載入完畢之后,我們就可以通過回調(diào)函數(shù)的adder參數(shù)來使用前面定義的匿名模塊。例子中可以看到,adder.js里存儲的是定義的匿名模塊,實際上我們可以用任何文件/路徑來包含這個模塊,為模塊的重用提供了方便(Java中的文件名/路徑和類名/包的必須一致性實際上就為類級別的重用造成了不便)。require函數(shù)用于載入任何一個模塊,后面將多次使用。
對于匿名模塊的使用有一些注意事項。比如每個文件中只能包含一個匿名模塊,而且匿名模塊只能被載入器載入,即只能用require來載入。也可以這么理解,實際上匿名模塊并不是沒有名字,而是在使用時進(jìn)行命名的模塊,例子中就是adder。?
數(shù)據(jù)封裝:新的JSON-P
對于一些僅僅提供數(shù)據(jù)或者獨立方法(不依賴于其它模塊的方法)的模塊,可以簡單的用如下方式來定義:?
define({?
? name:"some data"?
});?
這個和JSON-P非常像,但是卻有一個顯著的優(yōu)點:它使得JSON-P數(shù)據(jù)可以現(xiàn)在靜態(tài)文件中,而并不需要動態(tài)的回調(diào)過程。這也使得內(nèi)容是可cache的,而且是CDN友好的。?
?
封裝CommonJS模塊
CommonJS也是一套RIA框架,其中的模塊可以通過AMD來進(jìn)行封裝,從而可以用define的方式很容易的進(jìn)行異步裝載,在這里我們可以省略前2個參數(shù),僅包含回調(diào)函數(shù),但回調(diào)函數(shù)的第一個參數(shù)是require方法,第二個參數(shù)是exports對象,它定義了模塊本身,回調(diào)函數(shù)里的require的使用將被自動進(jìn)行動態(tài)加載。例如:?
define(function(require, exports){?
//math是標(biāo)準(zhǔn)CommonJS模塊:?
? var math = require("math");?
? exports.addTen = function(x){?
??? return math.add(x, 10);?
? };?
});??
需要注意這種形式要求模塊載入器掃描require函數(shù)。require調(diào)用必須寫成require(“…”)的形式才能被正確識別從而正常工作。這在一些瀏覽器不能正常工作(例如默寫版本的Opera移動版,以及PS3)。當(dāng)然,如果在部署前對代碼進(jìn)行了build,這將完全不成問題。你也可以封裝CommonJS模塊,并手動的指定依賴,這種方式使得我們也可以引用CommonJS變量,從而我們可以包含標(biāo)準(zhǔn)的require和exports變量:?
define(["require", "exports", "math"], function(require, exports){?
// standard CommonJS module:?
? var math = require("math");?
? exports.addTen = function(x){?
??? return math.add(x, 10);?
? };?
});??
??
完整的模塊定義
一個完整的模塊定義包含了模塊名,依賴,以及回調(diào)函數(shù)。這種形式的優(yōu)點是模塊可以包含在另外的文件中,或者可以用script標(biāo)記載入的地址中。這是build工具自動生成的規(guī)范模式,使得多個依賴可以被打包在同一個文件中,這種格式的例子如下:?
define("adder", ["math"], function(math){?
? return {?
??? addTen: function(x){?
????? return math.add(x, 10);?
??? }?
? };?
});
最后,我們來看有模塊id,但沒有模塊依賴的情況。這種情況用于你想指定模塊id,但是這個模塊不依賴于其它模塊。這時的參數(shù)默認(rèn)是“require”,“exports”和“module”。從而我們可以這樣創(chuàng)建adder模塊。?
define("adder", function(require, exports){?
? exports.addTen = function(x){?
????? return x + 10;?
? };?
});?
通過這種方式定義的模塊可以被RequireJS載入,也可以作為其它模塊的依賴被載入,或者直接用require()的形式載入。
綜上所述,這種API看似簡單,卻提供了一種極其靈活的方式來定義模塊,適用于各種應(yīng)用場景,從可被自由移動的匿名模塊,到構(gòu)建后的可被<script>標(biāo)記載入的模塊。當(dāng)前RequireJS和Dojo實現(xiàn)了這套規(guī)范,而JavaScript的Web Server框架NodeJS的Nodules也實現(xiàn)了這個規(guī)范。
AMD規(guī)范:簡單而優(yōu)雅的動態(tài)載入JavaScript代碼總結(jié)
以上是生活随笔為你收集整理的AMD规范:简单而优雅的动态载入JavaScript代码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: {HTML5}JQueryMobile页
- 下一篇: C++中的空类,编译器默认可以产生哪些成