AMD和CMD

AMD,js加載過多頁面中止響應,前端

使用js異步加載方式jquery

1.爲解決js加載阻塞json

2.解決js文件依賴的問題api

AMD規範:是 RequireJS 在推廣過程當中對模塊定義的規範化產出的,而CMD規範:是SeaJS 在推廣過程當中對模塊定義的規範化產出的。dom

什麼是CMD規範?異步

  在CMD中 一個模塊就是一個文件,以下代碼所示:async

//基本格式如:define(id, deps, factory)
//通常格式如:define(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:

   那麼如今我想在b.js裏面調用a.js裏面的a方法。咱們能夠以下作:函數

   define(function(require,exports){性能

        var fun = require('./a');jsonp

    console.log(fun.a()); // 就能夠調用到及執行a函數了。

       exports.a = function(){
    // 不少代碼
    };

   })

  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
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 都簡單純粹

相關文章
相關標籤/搜索