AMD規范與CMD規范的區別


AMD規范與CMD規范的區別是什么?

   在比較之前,我們得先來了解下什么是AMD規范?什么是CMD規范?當然先申明一下,我個人也是總結下而已,也是網上看到的資料,自己總結下或者可以說整理下而已,供大家更深入的了解!因為我們都知道 AMD規范:是 RequireJS 在推廣過程中對模塊定義的規范化產出的,而CMD規范:是SeaJS 在推廣過程中對模塊定義的規范化產出的。

什么是CMD規范?

  在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:
 require是一個方法,他可以解決依賴,用於獲取其他模塊提供的接口,比如下面的a.js代碼如下

  define(function(require, exports) {
    exports.a = function(){
    // 很多代碼
    };
  });

   那么現在我想在b.js里面調用a.js里面的a方法。我們可以如下做:

   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 則是異步回調執行。

 require.resolve(id)

使用模塊系統內部的路徑解析機制來解析並返回模塊路徑。該函數不會加載模塊,只返回解析后的絕對路徑。
define(function(require, exports) {

  console.log(require.resolve('./b'));
  // ==> http://example.com/path/to/b.js

});

exports

 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

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規范。

  什么是AMD規范?

如下官網代碼:
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方法。

其中上面的模塊名稱和依賴項 也可以省略,那么如果省略的話,那么我們可以稱他們為匿名函數,那么同樣 模塊名稱就是文件名稱 和上面的CMD規范類似。上面的['',''] 參數代表了一組對所定義的模塊來說必須的依賴項。第三個參數('definition function')是一個用來為你的模塊執行初始化的函數。一個最簡單的模塊可以以如下方式定義:
// 模塊定義函數 
// 依賴項(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 文件中或須要動態讀取依賴時加載代碼。用法的一個實例如下:

// 假設 '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
    };
});

 CMD規范與AMD規范的區別如下:

 1. CMD依賴就近:比如如下代碼

define(function(require,exports,module){  
        var a = require('./a');  
        a.doSomthing();  
});

   代碼在運行時,首先是不知道依賴的,需要遍歷所有的require關鍵字,找出后面的依賴。具體做法是將function toString后,用正則匹配出require關鍵字后面的依賴。

   而AMD依賴前置:如下代碼:

define(['./a','./b'],function(a,b){  
       //......  
       a.doSomthing();  
       //......  
       b.doSomthing();  
})  

代碼在一旦運行到此處,能立即知曉依賴。而無需遍歷整個函數體找到它的依賴,因此性能有所提升,缺點就是開發者必須顯式得指明依賴——這會使得開發工作量變大,比如:當依賴項有n個時候 那么寫起來比較煩 且容易出錯。不過 RequireJS 從 2.0 開始,也改成可以延遲執行(根據寫法不同,處理方式不同)。

2. 執行順序上:

  CMD是延遲執行的,而AMD是提前執行的。

3. api設計角度

  AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,沒有全局 require,而是根據模塊系統的完備性,提供 seajs.use 來實現模塊系統的加載啟動。CMD 里,每個 API 都簡單純粹


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM