在比較以前,咱們得先來了解下什麼是AMD規範?什麼是CMD規範?固然先申明一下,我我的也是總結下而已,也是網上看到的資料,本身總結下或者能夠說整理下而已,供你們更深刻的瞭解!由於咱們都知道 AMD規範:是 RequireJS 在推廣過程當中對模塊定義的規範化產出的,而CMD規範:是SeaJS 在推廣過程當中對模塊定義的規範化產出的。javascript
在CMD中 一個模塊就是一個文件,以下代碼所示:前端
//基本格式如:define(id, deps, factory) // 好比以下代碼 define('hello',['jQuery'],function(require, exports, module) { // 模塊代碼 });define是一個全局函數,主要是用來定於模塊的。其中如上'hello'就是模塊名稱,['jquery']是依賴項, 也能夠依賴於多項能夠以下寫法['jquery','',''],分別用逗號隔開, 其中上面的id(模塊名稱)和deps(被依賴項) 是能夠省略的。省略時,那麼模塊名稱就是文件名稱。 好比我有個文件叫a.js,那麼我定義模塊時候以下代碼所示:define(function(require, exports, module) { // 模塊代碼 })那麼若是我想在b.js代碼裏面要依賴於a.js的話,那麼我能夠直接這樣寫: define(function(require,exports,module){ var a = require('a') }); 可是注意:帶有id 和 deps 是不屬於CMD規範的。因此在seaJS裏面 通常的寫法是不帶模塊名稱和依賴項的。 就是如上的代碼格式。 下面看看 factory 在seajs裏面 factory既能夠是函數,對象或者字符串。factory爲對象 字符串時候, 表示該模塊的接口就是該對象或者字符串,以下能夠定義一個json對象。 define({"aa":'bb'}); 和jsonp格式相似,不過這樣的數據對象是高度可用的,並且由於是靜態對象,他也是CDN友好的,能夠提升性能 ,好比說咱們 有個省市區這麼一個jSON格式要返回咱們前端,若是以傳統JSONP的形式提供給客戶端, 它必須提供一個callback函數名,根據這個函數名動態生成返回數據,這使得標準JSONP數據必定不是CDN友好的。 那麼咱們能夠利用這種格式define({ provinces:[ { name: '上海', areas: ['浦東新區', '徐彙區']}, { name: '江蘇', cities: ['南京', '南通']} //..... ]});假設這個文件名爲china.js,那麼若是某個模塊須要這個數據,只須要: define(function(require,exports,module){ var china = require('./china'); //在這裏使用中國省市數據 }); 當factory爲函數時,表示該模塊的構造方法,執行該構造方法,能夠獲得模塊向外提供的接口。 默認會傳入三個參數require,exports,module.那麼咱們先來看看require參數吧require是一個方法,他能夠解決依賴,用於獲取其餘模塊提供的接口,好比下面的a.js代碼以下
define(function(require, exports) { exports.a = function(){ // 不少代碼 }; });那麼如今我想在b.js裏面調用a.js裏面的a方法。咱們能夠以下作:java
define(function(require,exports){ var fun = require('./a'); console.log(fun.a()); // 就能夠調用到及執行a函數了。 })require.async(id,callback) : require.async: 方法用來在模塊內部異步加載模塊,
並在加載完成後執行指定回調。callback參數可選。好比以下代碼:define(function(require, exports, module) { // 異步加載一個模塊,在加載完成時,執行回調 require.async('./b', function(b) { b.doSomething(); }); // 異步加載多個模塊,在加載完成時,執行回調 require.async(['./c', './d'], function(c, d) { c.doSomething(); d.doSomething(); }); });注意: require是同步往下執行的,而require.async 則是異步回調執行。使用模塊系統內部的路徑解析機制來解析並返回模塊路徑。該函數不會加載模塊,只返回解析後的絕對路徑。 define(function(require, exports) { console.log(require.resolve('./b')); // ==> http://example.com/path/to/b.js });exports:是一個對象,用來向外提供模塊接口。
好比仍是上面的代碼:以下a.js裏面define(function(require, exports) { exports.a = function(){ // 不少代碼 }; }); //或者以下書寫: define(function(require, exports) { return { i: 'a', a: function(){ // 執行相應的代碼 } } });那麼若是我在b.js裏面想要調用a.js裏面的a方法,因爲a.js使用exports對外提供了接口a方法,那麼在b.js裏面 咱們只須要先這樣 var fun = require('./a');而後執行fun.a();就能夠執行a方法了。module 是一個對象,上面存儲了與當前模塊相關聯的一些屬性和方法。其中exports是module.exports的一個引用
//moudle.id //模塊的惟一標識。以下代碼: define('id', [], function(require, exports, module) { // 模塊代碼 }); //module.uri //根據模塊系統的路徑解析規則獲得的模塊絕對路徑。 define(function(require, exports, module) { console.log(module.uri); // ==> http://example.com/path/to/this/file.js }); //等等屬性 具體能夠看seajs官網。原理是同樣的 由於seajs也採用的是CMD規範。
以下官網代碼:define("alpha", ["require", "exports", "beta"], function (require, exports, beta) { exports.verb = function() { return beta.verb(); //或者: return require("beta").verb(); } });這裏的require函數讓你可以隨時去依賴一個模塊,即取得模塊的引用,從而即便模塊沒有做爲參數定義,也可以被使用;exports是定義的 alpha 模塊的實體,在其上定義的任何屬性和方法也就是alpha模塊的屬性和方法。經過exports.verb = ...就是爲alpha模塊定義了一個verb方法。例子中是簡單調用了模塊beta的verb方法。jquery
其中上面的模塊名稱和依賴項 也能夠省略,那麼若是省略的話,那麼咱們能夠稱他們爲匿名函數,那麼一樣 模塊名稱就是文件名稱 和上面的CMD規範相似。上面的['',''] 參數表明了一組對所定義的模塊來講必須的依賴項。第三個參數('definition function')是一個用來爲你的模塊執行初始化的函數。一個最簡單的模塊能夠以以下方式定義:json
// 模塊定義函數 // 依賴項(foo 和 bar)被映射爲函數的參數 define('myMoudle',['foo','bar'],function(foo,bar){ // 返回一個定義了模塊導出接口的值 // (也就是咱們想要導出後進行調用的功能) // 在這裏建立模塊 var myModule = { doStuff:function(){ console.log('Yay! Stuff'); } } return myModule; }); //還能夠這樣書寫: // 另外一個例子能夠是... define('myModule',['math', 'graph'], function ( math, graph ) { // 請注意這是一個和 AMD 有些許不一樣的模式,但用幾種不一樣的方式 // 來定義模塊也是能夠的,由於語法在某些方面仍是比較靈活的 return { plot: function(x, y){ return graph.drawPie(math.randomGrid(x,y)); } } }; });另外一方面,require 則主要用來在頂層 JavaScript 文件中或需要動態讀取依賴時加載代碼。用法的一個實例以下:api
// 假設 'foo' 和 'bar' 是兩個外部模塊 // 在本例中,這兩個模塊被加載後的 'exports' 被當作兩個參數傳遞到了回調函數中 // 因此能夠像這樣來訪問他們 require(['foo', 'bar'], function ( foo, bar ) { // 這裏寫其他的代碼 foo.doSomething(); }); //動態加載的依賴項 以下代碼: define(function ( require ) { var isReady = false, foobar; // 請注意在模塊定義內部內聯的 require 語句 require(['foo', 'bar'], function (foo, bar) { isReady = true; foobar = foo() + bar(); }); // 咱們仍能夠返回一個模塊 return { isReady: isReady, foobar: foobar }; });
define(function(require,exports,module){ var a = require('./a'); a.doSomthing(); });
代碼在運行時,首先是不知道依賴的,須要遍歷全部的require關鍵字,找出後面的依賴。具體作法是將function toString後,用正則匹配出require關鍵字後面的依賴。dom
而AMD依賴前置:以下代碼:異步
define(['./a','./b'],function(a,b){ //...... a.doSomthing(); //...... b.doSomthing(); })
代碼在一旦運行到此處,能當即知曉依賴。而無需遍歷整個函數體找到它的依賴,所以性能有所提高,缺點就是開發者必須顯式得指明依賴——這會使得開發工做量變大,好比:當依賴項有n個時候 那麼寫起來比較煩 且容易出錯。不過 RequireJS 從 2.0 開始,也改爲能夠延遲執行(根據寫法不一樣,處理方式不一樣)。async
CMD是延遲執行的,而AMD是提早執行的。函數
AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一。好比 AMD 裏,require 分全局 require 和局部 require,都叫 require。CMD 裏,沒有全局 require,而是根據模塊系統的完備性,提供 seajs.use 來實現模塊系統的加載啓動。CMD 裏,每一個 API 都簡單純粹。