CMD和seaJS

來源:互聯網
上載者:User

標籤:out   改變   自動產生   target   動態   logs   方案   輸出   hello   

前面的話

  CMD(Common Module Definition)表示通用模組定義,該規範是國內發展出來的,由阿里的玉伯提出。就像AMD有個requireJS,CMD有個瀏覽器的實現SeaJS,SeaJS和requireJS一樣,都是javascript的模組化解決方案。本文將詳細介紹CMD和seaJS

 

CMD

  在Sea.js中,所有JavaScript模組都遵循CMD(Common Module Definition)模組定義規範。該規範明確了模組的基本書寫格式和基本互動規則

  AMD規範簡單到只有一個API,即define函數

define([module-name?], [array-of-dependencies?], [module-factory-or-object]);

  module-name: 模組標識,可以省略

  array-of-dependencies: 所依賴的模組,可以省略

  module-factory-or-object: 模組的實現,或者一個JavaScript對象

  CMD規範也與之類似,只不過第三個參數factory的實現方式不同。在CMD規範中,一個模組就是一個檔案。代碼的書寫格式如下

define(id?, deps?, factory)

  與AMD規範類似,define是一個全域函數,用來定義模組。字串 id 表示模組標識,數組 deps 是模組依賴。這兩個參數可以省略,通常由構建工具自動產生

  通常地,define()方法的第三個參數factory是一個函數,表示是模組的構造方法。執行該構造方法,可以得到模組向外提供的介面。factory 方法在執行時,預設會傳入三個參數:requireexports 和 module

  [注意]factory()方法的參數如果不需要,可以省略,但不可以修改,如修改為‘a‘、‘b‘、‘c‘,也不可以改變其參數的順序。在函數內部,也不能對參數名重新賦值,如‘var a = require; ‘

define(function(require, exports, module) {  // 模組代碼});

【require】

  require 是 factory 函數的第一個參數。require 是一個方法,接受 模組標識 作為唯一參數,用來擷取其他模組提供的介面。通俗地說,通過require()方法來調用其他模組的屬性或方法

define(function(require, exports, module) {  // 擷取模組 a 的介面  var a = require(‘./a‘);  // 調用模組 a 的方法  a.doSomething();});

  這個require()方法的實現和功能都特別類似於CommonJS中的require()方法。或許,有人會有疑惑,require()不是一個同步方法嗎?在CommonJS中是的,在seaJS中也可以這麼說,但並不完整。更合理的說法應該是,模組內的同步載入,實際表現為對模組a進行預下載

  例如下面的代碼,即使不點擊頁面,a.js也會預先下載。點擊頁面後,控制台依次輸出‘a‘和‘a.test‘

// main.jsdefine(function(require, exports, module){    document.onclick = function(){        var a = require(‘js/a‘);        a.test();    }    });define(function(require, exports, module){    console.log(‘a‘);    exports.test = function(){        console.log(‘a.test‘);    }})

  能不能執行時再下載呢?類似於懶載入。有的,使用require.async()方法。require.async 方法用來在模組內部非同步載入模組,並在載入完成後執行指定回調

// main.jsdefine(function(require, exports, module){    document.onclick = function(){        require.async(‘./a‘,function(a){            a.test();        });    }    });//a.jsdefine(function(require, exports, module){    console.log(‘a‘);    exports.test = function(){        console.log(‘a.test‘);    }})

【exports】

  exports 是一個對象,用來向外提供模組介面。與CommonJS的exports功能類似

define(function(require, exports) {  // 對外提供 foo 屬性  exports.foo = ‘bar‘;  // 對外提供 doSomething 方法  exports.doSomething = function() {};});

  除了給 exports 對象增加成員,還可以使用 return 直接向外提供介面,這種方式與requireJS的方式類似

define(function(require) {  // 通過 return 直接提供介面  return {    foo: ‘bar‘,    doSomething: function() {}  };});

  如果 return 語句是模組中的唯一代碼,還可簡化為

define({  foo: ‘bar‘,  doSomething: function() {}});

【module】

  module 是一個對象,上面儲存了與當前模組相關聯的一些屬性和方法

// main.jsdefine([‘./a‘],function(require, exports, module){    console.log(module);})

  module.uri表示根據模組系統的路徑解析規則得到的模組絕對路徑

  module.id是模組的唯一標識,一般情況下沒有在define中手寫id參數時,module.id的值就是module.uri,兩者完全相同

  module.dependencies是一個數組,表示當前模組的依賴

  module.exports是當前模組對外提供的介面。傳給factory構造方法的exports參數是module.exports對象的一個引用。只通過exports參數來提供介面,有時無法滿足開發人員的所有需求。 比如當模組的介面是某個類的執行個體時,需要通過module.exports來實現

  [注意]對module.exports的賦值需要同步執行,不能放在回呼函數裡。下面這樣是不行的

define(function(require, exports, module) {  // 錯誤用法  setTimeout(function() {    module.exports = { a: "hello" };  }, 0);});

 

入口

  requireJS通過data-main來設定入口,而seaJS則通過sea.use()來設定。sea.js 在下載完成後,會自動載入入口模組

seajs.use(id, callback?)

  [注意]callback參數可選,省略時,表示無需回調

<script src="sea.js"></script><script>  seajs.use(‘js/main‘);</script>

  載入單個依賴,運行以下代碼後,控制台輸出‘test‘

//index.html<script src="sea.js"></script><script>    seajs.config({        base: ‘js‘    });    seajs.use("main",function(a){        a.test();    });</script>// main.jsdefine([‘./a‘],function(require, exports, module){    return {        test : function(){            console.log(‘test‘);        }    }})

  載入多個依賴

//並發載入模組 a 和模組 b,並在都載入完成時,執行指定回調seajs.use([‘./a‘, ‘./b‘], function(a, b) {  a.init();  b.init();});

【DOMReady】

  seajs.useDOM ready事件沒有任何關係。如果某些操作要確保在DOM ready後執行,需要使用jquery等類庫來保證

seajs.use([‘jquery‘, ‘./main‘], function($, main) {  $(document).ready(function() {    main.init();  });});

【打包】

  引入 sea.js 時,可以把 sea.js 與其他檔案打包在一起,可提前合并好,或利用 combo 服務動態合并。無論哪一種方式,為了讓 sea.js 內部能快速擷取到自身路徑,推薦手動加上 id 屬性

<script src="path/to/sea.js" id="seajsnode"></script>

  加上 seajsnode 值,可以讓 sea.js 直接擷取到自身路徑,而不需要通過其他機制去自動擷取。這對效能和穩定性會有一定提升,推薦預設都加上

 

配置

【路徑】

  如果不配置路徑,在requireJS中,預設路徑是data-main的所處目錄,比如data-main=‘js/main‘,則所處路徑是‘js‘目錄下

  而seaJS則不同,它的預設路徑是seaJS檔案的所處目錄,比如seaJS檔案所處路徑是‘demo‘目錄下,進行如下入口設定後

seajs.use(‘js/main‘);

  說明main.js的目錄為‘demo/js/main.js‘。如果main.js依賴於a.js,且a.js與main.js處於同一目錄下,則以下兩種寫法都正確

  1、‘demo‘ + ‘js/a‘ = ‘demo/js/a.js‘

// main.jsdefine([‘js/a‘],function(require, exports, module){    })

  2、‘./‘表示目前的目錄,即‘demo/js‘,所以 ‘./a‘ = ‘demo/js/a.js‘

// main.jsdefine([‘./a‘],function(require, exports, module){    })

  在requireJS中使用baseUrl來配置基礎路徑,而在seaJS中使用base。進行如下配置後,真實路徑為 ‘demo‘ + ‘js‘ + ‘main‘ = ‘demo/js/main.js‘

<script src="sea.js"></script><script>    seajs.config({        base: ‘js‘    });    seajs.use("main");</script>

【別名】

  當模組標識很長時,可以使用 alias 來簡化

seajs.config({  alias: {    ‘jquery‘: ‘jquery/jquery/1.10.1/jquery‘,    ‘app/biz‘: ‘http://path/to/app/biz.js‘,  }});

【目錄】

  當目錄比較深,或需要跨目錄調用模組時,可以使用 paths 來簡化書寫

seajs.config({  paths: {    ‘gallery‘: ‘https://a.alipayobjects.com/gallery‘,    ‘app‘: ‘path/to/app‘,  }});

 

與AMD區別

  AMD 是 RequireJS 在推廣過程中對模組定義的正常化產出,CMD 是 SeaJS 在推廣過程中對模組定義的正常化產出。這些規範的實現都能達成瀏覽器端模組化開發的目的

  AMD與CMD主要有以下兩點區別

  1、所相依模組的執行時機

  對於依賴的模組,AMD是提前執行,CMD是順延強制

  AMD在載入模組完成後就會執行該模組,所有模組都載入執行完後會進入require的回呼函數,執行主邏輯,這樣的效果就是相依模組的執行順序和書寫順序不一定一致,看網路速度,哪個先下載下來,哪個先執行,但是主邏輯一定在所有依賴載入完成後才執行。不過,新版本的RequireJS也可以順延強制

  CMD載入完某個相依模組後並不執行,只是下載而已,在所有相依模組載入完成後進入主邏輯,遇到require語句的時候才執行對應的模組,這樣模組的執行順序和書寫順序是完全一致的。如果使用require.async()方法,可以實現模組的懶載入,即不執行不下載

  2、CMD推崇依賴就近,AMD推崇依賴前置

// CMDdefine(function(require, exports, module) {     var a = require(‘./a‘)     a.doSomething()      // 此處略去 100 行       var b = require(‘./b‘) // 依賴可以就近書寫      b.doSomething()       // ... })
// AMDdefine([‘./a‘, ‘./b‘], function(a, b) {  // 依賴必須一開始就寫好    a.doSomething()        // 此處略去 100 行        b.doSomething()        ...})

  當然,AMD也支援CMD的寫法,同時還支援將require作為依賴項傳遞

 

最後

  CommonJS、requireJS、seaJS這三種模組化方案,並沒有高低之分。隨著各個方案的不斷升級,語言方面相互借鑒,使用差異逐漸層小。以上三種庫層級的模組化方案,需要引入額外的庫,且所遵循的規範並不是標準組織制定的,權威性不足

  隨著ES6在語言層面上開始支援模組化,ES6的模組化寫法才是未來的模組化標準

CMD和seaJS

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.