對CommonJS、AMD、CMD簡單粗暴的理解

  對於大型Web應用或者項目,動輒上萬行的代碼,給開發和後期維護帶來了不小的麻煩。所以,須要有一種規範化的模塊管理機制,幫助開發者集中處理模塊的定義與調用關係。node

  在ES6正式出臺前,已經有很多人致力於推出適合Web開發的模塊化管理標準,CommonJS、AMD和CMD就是其中的成功表明。git

  如下爲我查閱資料後,對三者最直觀的理解:github

CommonJS

  一般被應用於服務器,實現表明:NodeJS。NodeJS相信你們都不陌生,它的出現成功將Javascript應用到了服務器端,使得前段開發者也能較爲省力得轉向後端開發,而無需學習一門新語言。json

  在服務器端,模塊的加載和執行都在本地完成,所以,CommonJS並不要求模塊加載的異步化。後端

模塊定義與加載

  • 對於CommonJS,模塊以文件爲單位存在,模塊實現所有位於該文件內部
  • 在文件末尾,須要把將要導出的方法添加到module.exports對象上
  • 隨後在其餘文件(模塊)中,可使用require()方法加載須要的模塊,該方法要求一個參數:能夠是一個模塊名(此時加載的是默認提供的模塊),或者是一個URL。若是是URL,其能夠是相對路徑或絕對路徑,或者是一個指定的路徑(由Node自行解析並尋找)。關於文件的後綴名,默認爲「.js」,所以參數中能夠省略後綴名;而若是指定的模塊未發現,則會繼續尋找以「.json」和「.node」爲後綴的文件(其中以「.node」爲後綴的文件將會以編譯後的二進制文件格式解析)。

AMD

  AMD(異步模塊加載)和CMD一般用於瀏覽器端,它們與CommonJS最明顯的不一樣就是異步加載。AMD的實現表明是require.js,它也是require.js在推廣過程當中的附加產物。數組

模塊定義與加載

  • AMD模塊不必定以文件爲單位,小模塊集羣也是容許的;但基本上在開發過程當中,仍是應當以文件的形式進行管理
  • 模塊的定義由define()方法肯定,該方法接受兩個參數:
    • 一是當前模塊的依賴模塊,以數組形式傳遞
    • 二是當前模塊的實現,以回調形式傳遞。一中的依賴經過參數傳給回調。在回調末尾,以對象的形式返回須要公開的方法組。
  • 模塊的配置使用require.config()方法,它接受一個對象類型的參數,該對象須要配置一些屬性:baseUrl,paths,shim等
    • baseUrl:全部模塊查找的根路徑;未設置時默認是使用require.js的HTML文件所在目錄。或者可使用data-main屬性在加載require.js的標籤中定義根路徑。
    • callback:當前依賴所有加載完成後的回調函數
    • config:將Application級別的配置信息傳遞給模塊時使用。傳遞時使用module.config()方法。
      requirejs.config({
      config: {
      'bar': {
      	size:'large'
      },
      'baz': {
      	color: 'blue'
              }
          }
      });
      //bar.js直接使用module模塊
      define(function (require, exports, module) {
          var size = module.config().size;
      });
      //baz.js使用了一個依賴數組,並要求一個特殊的依賴「module」
      define(['module'], function(module) {
          var color = module.config().color;
      });

      當「some/newmodule」調用了「require('foo')」,它將獲取到foo1.2.js文件;而當「some/oldmodule」調用「`require('foo')」時它將獲取到foo1.0.js。瀏覽器

    • exports:模塊的輸出
    • init:模塊的初始化工做
    • paths:模塊文件的路徑。當paths中以/開頭、或以.js結尾、或包含協議時(如http://...),其路徑不在根路徑下。
    • shim:須要未用define()方法定義的模塊時使用。值爲一組模塊對象,每一個對象分別有一些屬性:deps,exports,init等。值得注意的是,shim只是定義了模塊的依賴關係,仍然須要經過define+require的方式調用。
      • deps:模塊的依賴數組
      • exports:模塊的輸出
    • map:對於給定的模塊前綴,使用一個不一樣的模塊ID來加載該模塊。可使用*號做爲默認配置,且該配置能夠被更具體的配置覆蓋。
      requirejs.config({
      	map: {
      	    'some/newmodule': {
      	        'foo': 'foo1.2'
      	    },
      	    'some/oldmodule': {
      	        'foo': 'foo1.0'
      	    }
      	}
      });	
    • 更多參數請戳 參考連接

 CMD

  CMD(通用模塊加載)是sea.js在推廣過程當中的產出,它與AMD主要有如下幾點區別(來自seajs的官方闡述):服務器

  • 定位有差別。RequireJS 想成爲瀏覽器端的模塊加載器,同時也想成爲 Rhino / Node 等環境的模塊加載器。Sea.js 則專一於 Web 瀏覽器端,同時經過 Node 擴展的方式能夠很方便跑在 Node 環境中。
  • 遵循的規範不一樣。RequireJS 遵循 AMD(異步模塊定義)規範,Sea.js 遵循 CMD (通用模塊定義)規範。規範的不一樣,致使了二者 API 不一樣。Sea.js 更貼近 CommonJS Modules/1.1 和 Node Modules 規範。
  • 推廣理念有差別。RequireJS 在嘗試讓第三方類庫修改自身來支持 RequireJS,目前只有少數社區採納。Sea.js 不強推,採用自主封裝的方式來「海納百川」,目前已有較成熟的封裝策略。
  • 對開發調試的支持有差別。Sea.js 很是關注代碼的開發調試,有 nocache、debug 等用於調試的插件。RequireJS 無這方面的明顯支持。
  • 插件機制不一樣。RequireJS 採起的是在源碼中預留接口的形式,插件類型比較單一。Sea.js 採起的是通用事件機制,插件類型更豐富。
  • AMD提倡依賴前置,也就是在一開始就定義加載。而CMD則推崇依賴就近,即就在使用到模塊的代碼前面進行依賴加載。這裏就須要注意了,使用requirejs會按照模塊的依賴順序進行加載,即模塊不會按照代碼裏的順序進行加載,可能形成意外地結果。

    這造成了兩種大相徑庭的加載方式:「預加載」和「懶加載」。AMD提早將全部模塊的全部依賴加載完成後,纔開始執行主流程;而CMD是遇到一個依賴開始加載,完成後執行當前流程,遇到下一個依賴再次去加載,而後再執行下一步。固然,同一模塊的依賴之間仍然是異步加載的。異步

模塊定義與加載

  流程與AMD相似,再也不贅述,只簡單介紹seajs的API。模塊化

  • cache:查看當前模塊系統中的模塊信息
  • config:配置模塊參數,參數列表:
    • alias:模塊別名
    • base:根路徑
    • paths:模塊文件所在路徑
    • vars:變量配置。好比須要在運行時肯定模塊路徑的狀況:
      seajs.config({
          // 變量配置
          vars: {
              'locale': 'zh-cn'
          }
      });
      define(function(require, exports, module) {
        var lang = require('./i18n/{locale}.js');
           //=> 加載的是 path/to/i18n/zh-cn.js
      });

      使用變量須要用花括號包圍,如例中的{locale}。

  • data:查看 seajs 全部配置以及一些內部變量的值,可用於插件開發。當加載遇到問題時,也可用於調試。
  • resolve:利用模塊系統的內部機制對傳入的字符串參數進行路徑解析。
  • use:加載模塊。seajs.use(id/url/urlArray, callback)
相關文章
相關標籤/搜索