1. 程式人生 > >淺析JS模組規範:AMD和CMD

淺析JS模組規範:AMD和CMD

在瞭解AMDCMD規範前,我們先來簡單地瞭解下什麼是模組?
簡單的說,一個模組就是實現特定功能的檔案,有了模組,我們就可以更方便地使用別人的程式碼,想要什麼功能,就載入什麼模組。當然,模組開發需要遵循一定的規範,否則各用各的就會亂套了。
目前,常用的JS模組規範主要有兩種:CMDAMDAMD AMD,非同步模組定義(Asynchronous Module Definition),它是依賴前置 (依賴必須一開始就寫好)會先儘早地執行(依賴)模組 。換句話說,所有的require都被提前執行(require 可以是全域性或區域性 )。 AMD規範只定義了一個函式 define
,它是全域性變數。用法:
defind(id, dependencies, factory)
引數說明:
  • id:字串型別,指定義中模組的名稱,可選。如果沒有提供該引數,模組的名稱應該預設為模組載入器請求的指定指令碼的名稱。如果提供了該引數,模組名必須是“頂級”的和絕對的(不允許相對名稱)。
  • dependencies:array型別,包含一組當前模組依賴的,已被模組定義的模組標識。
依賴引數是可選的,如果忽略此引數,它應該預設為["require", "exports", "module"]。然而,如果工廠方法的長度屬性小於3,載入器會選擇以函式的長度屬性指定的引數個數呼叫工廠方法。
  • factory
    :函式(工廠方法),模組初始化要執行的函式或物件。如果為函式,它應該只被執行一次。如果是物件,此物件應該為模組的輸出值。
模組名的格式 模組名用來唯一標識定義中模組,它們同樣在依賴性陣列中使用:

模組名是用正斜槓分割的有意義單詞的字串  

單詞須為駝峰形式,或者"."".."  

模組名不允許副檔名的形式,如“.js”  

模組名可以為 "相對的""頂級的"。如果首字元為“.”或“..”則為相對的模組名  

頂級的模組名從根名稱空間的概念模組解析  

相對的模組名從 "require" 書寫和呼叫的模組解析

簡單例項: 首先在建立一個index.html,內容如下:
<!DOCTYPE html>  

<html lang="en">  

<head>   

  <meta charset="UTF-8">   

  <title>AMD</title>  

</head>  

<body>   

  <script data-main="scripts/main" src="require.js"></script>  

</body>  

</html>


在上面的程式碼中,我們引入了require.js,然後使用data-main屬性指定入口檔案為scripts/main(這裡省略字尾.js)。 然後在index.html同級下建立一個資料夾scripts,跟著建立三個js檔案:a.js、b.js、mian.js,程式碼如下:
/* 

*  a.js 

*  建立一個名為“a”的模組

*/



define('a', function(require, exports, module) {   

  exports.getTime = function() {   

    return new Date();   

  }  

});



/* 

*  b.js 

*  建立一個名為“b”的模組,同時使用依賴require、exports和名為“a”的模組:

*/

define('b', ['require', 'exports', 'a'], function(require, exports, a) {   exports.test = function() {

    return {   

      now: a.getTime()    

    };   

  }  

});



/* main.js */

require(['b'], function(b) {   

  console.log(b.test());  

});


CMD
CMD(Common Module Definition)更貼近 CommonJS Modules/1.1 和 Node Modules 規範,一個模組就是一個檔案;它推崇依賴就近,想什麼時候 require 就什麼時候載入,實現了懶載入(延遲執行 ) ;它也沒有全域性 require, 每個API都簡單純粹 。
在 CMD 規範中,一個模組就是一個檔案。程式碼的書寫格式如下:
define(factory);
factory 為函式時,表示是模組的構造方法。執行該構造方法,可以得到模組向外提供的介面。factory 方法在執行時,預設會傳入三個引數:require、exports 和 module
define(function(require, exports, module) {    

  // 模組程式碼  

});
簡單例項: 建立一個index.html,內容如下:
<!DOCTYPE html>  

<html lang="en">  

<head>   

  <meta charset="UTF-8">   

  <title>CMD</title>  

</head>  

<body>     

  <script src="sea.js"></script>   

  <script>   

    /* 載入入口模組 */

    seajs.use('./scripts/main');   

  </script>  

</body>  

</html>
然後在index.html同級下建立一個scripts資料夾,跟著建立兩個js檔案:a.js、main.js,程式碼如下:
/* 

*  a.js 

*  一個檔案就是一個模組

*/

define(function(require, exports, module) {   

  exports.getTime = function() {   

    return new Date();   

  }  

});



/* main.js */

define(function(require, exports, module) {  

  /* 按需載入a.js */ 

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

  console.log(a.getTime());  

});
RequireJSSea.js共同點
  • RequireJS 和 Sea.js 都是模組載入器
  • 定位有差異。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的比較
  • AMD:依賴前置,預執行(非同步載入:依賴先執行)。CMD:依賴就近,懶(延遲)執行(執行到需載入,根據順序執行)
// CMD
define(function(require, exports, module) {  

  var a = require('./a')  

  a.doSomething();  

  // 省略1萬行 

  var b = require('./b') // 依賴可以就近書寫  

  b.doSomething();

})

// AMD 預設推薦的是
define(['./a', './b'], function(a, b) { // 依賴必須一開始就寫好  

  a.doSomething();  

  // 省略1萬行  

  b.doSomething();

}) 
著作權歸作者所有。
商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
原文: http://ghmagical.com/article/page/id/N7VY7Hg4TlgW © ghmagical.com