AMD CMD
AMD,CMD是瀏覽器端模塊加載器的兩種規(guī)范。AMD的代表是requireJS和SeaJS。今天主要研究這倆玩意的區(qū)別。
規(guī)范區(qū)別
AMD
define(id?, deps?, factory(...deps) {});
一個需要用到jQuery和Underscore的模塊會寫成這樣:
define(['jQuery', 'Underscore'], function ($, _) {
// use $ and _ to do sth...
return {
// export
}
});
CMD
define(factory(require, exports, module) {})
更像是CommonJS和AMD的結(jié)合;因為這個factory跟Node中的函數(shù)包裝器幾乎是一樣的……用法也很像,require通過路徑標識引入依賴,exports和module都可以用來導出模塊。
同樣引入jQuery和Underscore的CMD模塊:
define(factory(require, exports, module) {
var $ = require('jQuery'),
_ = require('Underscore');
// use $ and _ to do sth...
exports = module.exports = {
// exports;
}
});
實現(xiàn)區(qū)別
主模塊的指定
requireJS通過在script節(jié)點中指定data-main來指定主模塊;主模塊通過requireAPI來引入依賴并繼續(xù)執(zhí)行代碼;
seaJS通過seajs.use來生成匿名模塊作為主模塊。
加載順序
我只看過Sea的源碼……所以requireJS是靠猜的……猜錯了就算了……
Sea中對于每個define聲明的模塊,都會轉(zhuǎn)化為一個中間形式define(ids?, deps?, factory)。這個也可以直接在Sea中直接這樣寫,只不過這不屬于CMD規(guī)范而已。
怎么轉(zhuǎn)化的呢……factory.toString()然后正則匹配require找依賴,然后依賴前置。所以在Sea中使用require是做不到動態(tài)引入的,因為依賴前置這個階段是靜態(tài)分析啊……
當然,Sea也提供了動態(tài)引入的API,所謂require.async,嗯,看過源碼就知道,require.async = seajs.use……
扯遠了,繼續(xù)說。依賴前置階段結(jié)束后,就會繼續(xù)開始加載這個模塊所依賴的模塊。
再然后,區(qū)別來了。這個時候,該模塊所有的依賴都已經(jīng)加載完了,requireJS就開始執(zhí)行factory函數(shù)了,并且將模塊結(jié)果緩存。而Sea中factory的執(zhí)行是在require函數(shù)里寫的,意思就是只有執(zhí)行require了才會執(zhí)行模塊的factory方法。
說簡單點,因為AMD規(guī)范的依賴前置特性,所有依賴模塊的代碼都會被執(zhí)行,不論這個依賴的代碼是否被用到了。
而CMD這看似是動態(tài)引入的require,雖然同樣下載了代碼,但是只有真正執(zhí)行了require函數(shù)才會執(zhí)行模塊代碼。
所以requireJS擁有更多的初始代碼,以及沒有動態(tài)引入;而Sea則代碼執(zhí)行過程中會執(zhí)行更多的模塊代碼。