
繼續(xù)前篇,各種模塊化規(guī)范開始推出,其中比較突出的是服務(wù)器端的 CommonJS 規(guī)范,它是 Nood.JS 在實(shí)踐中推出的,也是首先采用 JS 模塊化概念的語言,跳出了瀏覽器;進(jìn)而出現(xiàn)了瀏覽器環(huán)境的模塊化方案 AMD和CMD。
CommonJS Modules/1.0
CommonJS 規(guī)范是服務(wù)器端的模塊化的規(guī)范,是 Nood.js 在實(shí)踐中推出的,Nood.js 也是首先采用 js 模塊化的;
它規(guī)定一個(gè)單獨(dú)的文件就是一個(gè)模塊,一個(gè)模塊中存在一個(gè)自由變量 require,這是個(gè)函數(shù),用于加載模塊:
- 這個(gè)
require函數(shù)接受一個(gè)模塊標(biāo)識符,返回外部模塊所輸出的API; - 如果出現(xiàn)依賴閉環(huán)(dependency cycle),那么外部模塊在被它的傳遞依賴(transitive dependencies)所
require的時(shí)候可能并沒有執(zhí)行完成;在這種情況下,"require"返回的對象必須至少包含此外部模塊在調(diào)用require函數(shù)(會進(jìn)入當(dāng)前模塊執(zhí)行環(huán)境)之前就已經(jīng)準(zhǔn)備完畢的輸出。 - 如果請求的模塊不能返回,那么"require"必須拋出一個(gè)錯(cuò)誤。
在一個(gè)模塊中,會存在一個(gè)名為 exports 的自由變量,這是一個(gè)對象,模塊可以在執(zhí)行的時(shí)候把自身的API加入到其中,用于定義模塊,導(dǎo)出給其他地方使用;
exports 對象是輸出模塊變量的唯一方式。
參照下面的一個(gè)例子:
//math.js
exports.add = function(a,b){
var c = a + b;
return c;
}
//index.js
var add = require('math').add;//
console.log(add(1,1));//2
在 math.js中將 add 函數(shù)綁定到模塊中的 exports 對象中,之后在 index.js 模塊中用 require 方法加載了 math.js 模塊,并調(diào)用該模塊中的 add 函數(shù)。
AMD
Asynchronous Module Definition,即異步的模塊定義,是瀏覽器端的模塊化規(guī)范,是 RequireJS 在推廣過程中對模塊定義的規(guī)范化產(chǎn)出。
與服務(wù)器端的模塊化規(guī)范 CommonJS 不同,AMD 的模塊加載是異步的,因?yàn)槭菫g覽器端,所以勢必要是異步的(瀏覽器同步加載模塊會導(dǎo)致性能、可用性、調(diào)試和跨域訪問等問題)。因?yàn)槟K異步加載時(shí)不會影響后面程序的執(zhí)行,前面總結(jié)過 js 異步的情況,依賴某些模塊的語句均放置在回調(diào)函數(shù)中,等待模塊加載完成后再執(zhí)行;
AMD 規(guī)范只定義了一個(gè)函數(shù) define ,是一個(gè)全局變量,如下定義一個(gè)模塊的語法:
define(id?, dependencies?, factory);
id:模塊的名字,如果沒有提供該參數(shù),模塊的名字應(yīng)該默認(rèn)為模塊加載器請求的指定腳本的名字;dependencies:模塊的依賴,已被模塊定義的模塊標(biāo)識的數(shù)組字面量。依賴參數(shù)是可選的,如果忽略此參數(shù),它應(yīng)該默認(rèn)為["require", "exports", "module"]。然而,如果工廠方法的長度屬性小于3,加載器會選擇以函數(shù)的長度屬性指定的參數(shù)個(gè)數(shù)調(diào)用工廠方法。factory:模塊的工廠函數(shù),模塊初始化要執(zhí)行的函數(shù)或?qū)ο蟆H绻麨楹瘮?shù),它應(yīng)該只被執(zhí)行一次。如果是對象,此對象應(yīng)該為模塊的輸出值。
參照下面的一個(gè)例子:
define('myModule',['jQuery','types/Employee'],function($,Employee){//定義模塊myModule,引入依賴jQuery,types/Employee
function Programmer(){
//do something
};
Programmer.prototype = new Employee();
return Programmer; //return Constructor
})
CMD
Common Module Definition,即通用模塊定義,是瀏覽器端的模塊化規(guī)范,是 SeaJS 在推廣過程中對模塊定義的規(guī)范化產(chǎn)出。
如下定義一個(gè)模塊的語法:
define(factory)
-
factory為函數(shù)時(shí),表示是模塊的構(gòu)造方法。執(zhí)行該構(gòu)造方法,可以得到模塊向外提供的接口。factory 方法在執(zhí)行時(shí),默認(rèn)會傳入三個(gè)參數(shù):require、exports 和 module.
AMD 是依賴關(guān)系前置,提前執(zhí)行;CMD 是類似于 CommonJS 那樣 按需加載,延遲執(zhí)行:
//CMD recommanded
define(function(require, exports, module){
var a = require('a');
a.doSomething();
var b = require('b');
b.doSomething(); // 依賴就近,延遲執(zhí)行
});
//AMD recommanded
define(['a', 'b'], function(a, b){
a.doSomething(); // 依賴前置,提前執(zhí)行
b.doSomething();
});
明顯看出和 AMD 不同,模塊定義時(shí)已不用立馬引入依賴,而是運(yùn)行到需要時(shí)候再加載,根據(jù)順序執(zhí)行,這樣更像是 CommonJS 的風(fēng)格,讓人感覺也像是同步加載似的。但實(shí)際上 CMD 內(nèi)部處理是對文件做了一個(gè)詞法的解析,在還沒執(zhí)行的時(shí)候,解析出所需的依賴,并不是真正的同步。
參考: