JS中的模塊規范(CommonJS,AMD,CMD)
CommonJS規范-是用在服務器端的(不能用在瀏覽器端),同步的,如nodejs
AMD規范, CMD規范是用在瀏覽器端的,異步的,如RequireJS 和SeaJS
AMD 是 RequireJS 在推廣過程中對模塊定義的規范化產出。
CMD 是 SeaJS 在推廣過程中對模塊定義的規范化產出。
其中,AMD 先提出(國外),CMD 是根據commonjs和amd基礎上提出的(國內-玉伯)。
RequireJS 遵循AMD規范,CMD和AMD基本相同,最大的區別是就CMD是懶加載,AMD是預加載.
簡單來說,就是SeaJS 屬於懶加載,RequireJS屬於預加載(RequireJS從2.0開始,也改成可以延遲執行(根據寫法不同,處理方式不通過))。
1.首先原理上的區別
sea.js遵循CMD規范.書寫方式類似node.js的書寫模板代碼.依賴的自動加載,配置的簡潔清晰.說白了就是懶加載.
在這里,順便擴展一下預加載和懶加載的優缺點
預加載:當第一次訪問時將所有的文件加載出來
優點:第一次訪問完成以后, 再次訪問的速度會很快
缺點:第一次加載頁面要等待很久.
懶加載:使用的時候才會加載對應的文件.
優點:第一次訪問速度相對快點
缺點:再訪問其他新的模塊時速度會變慢.
2.書寫上面的區別
都是用define來定義一個模板.通過require,exports,module三個參數來調動函數.
基本上他們的用法是大同小異的.不過要兩點較大的區別是需要大家去注意的:
1)sea.js使用模塊時用方法seajs.use,而require.js直接用require關鍵字
2)sea.js只使用一個模塊時可以只傳入一個字符串,但是require傳入的必須是一個數組.
CommonJS
CommonJs 是服務器端模塊的規范,Node.js采用了這個規范。
2009年,美國程序員Ryan Dahl創造了node.js項目,將javascript語言用於服務器端編程。這標志"Javascript模塊化編程"正式誕生。因為老實說,在瀏覽器環境下,沒有模塊也不是特別大的問題,畢竟網頁程序的復雜性有限;但是在服務器端,一定要有模塊,與操作系統和其他應用程序互動,否則根本沒法編程。NodeJS是CommonJS規范的實現,webpack 也是以CommonJS的形式來書寫。
基於commonJS規范的nodeJS出來以后,服務端的模塊概念已經形成,很自然地,大家就想要客戶端模塊。而且最好兩者能夠兼容,一個模塊不用修改,在服務器和瀏覽器都可以運行。但是,由於一個重大的局限,使得CommonJS規范不適用於瀏覽器環境。還是上面的代碼,如果在瀏覽器中運行,會有一個很大的問題,你能看出來嗎?
var math = require('math');
math.add(2, 3);
第二行math.add(2, 3),在第一行require('math')之后運行,因此必須等math.js加載完成。也就是說,如果加載時間很長,整個應用就會停在那里等。您會注意到 require
是同步的。
這對服務器端不是一個問題,因為所有的模塊都存放在本地硬盤,可以同步加載完成,等待時間就是硬盤的讀取時間。但是,對於瀏覽器,這卻是一個大問題,因為模塊都放在服務器端,等待時間取決於網速的快慢,可能要等很長時間,瀏覽器處於"假死"狀態。
因此,瀏覽器端的模塊,不能采用"同步加載"(synchronous),只能采用"異步加載"(asynchronous)。這就是AMD規范誕生的背景。
CommonJS是主要為了JS在后端的表現制定的,他是不適合前端的,AMD(異步模塊定義)出現了,它就主要為前端JS的表現制定規范。
根據CommonJS規范,一個單獨的文件就是一個模塊。加載模塊使用require方法,該方法讀取一個文件並執行,最后返回文件內部的exports對象。
例如:
// foobar.js
//私有變量
var test = 123;
//公有方法
function foobar () {
this.foo = function () {
// do someing ...
}
this.bar = function () {
//do someing ...
}
}
//exports對象上的方法和變量是公有的
var foobar = new foobar();
exports.foobar = foobar;
//require方法默認讀取js文件,所以可以省略js后綴
var test = require('./boobar').foobar;
test.bar();
CommonJS 加載模塊是同步的,所以只有加載完成才能執行后面的操作。像Node.js主要用於服務器的編程,加載的模塊文件一般都已經存在本地硬盤,所以加載起來比較快,不用考慮異步加載的方式,所以CommonJS規范比較適用。但如果是瀏覽器環境,要從服務器加載模塊,這是就必須采用異步模式。所以就有了 AMD CMD 解決方案。
AMD((Asynchromous Module Definition)
AMD 是 RequireJS 在推廣過程中對模塊定義的規范化產出
AMD異步加載模塊。它的模塊支持對象 函數 構造器 字符串 JSON等各種類型的模塊。
適用AMD規范適用define方法定義模塊。
//通過數組引入依賴 ,回調函數通過形參傳入依賴
define(['someModule1', ‘someModule2’], function (someModule1, someModule2) {
function foo () {
/// someing
someModule1.test();
}
return {foo: foo}
});
AMD規范允許輸出模塊兼容CommonJS規范,這時define方法如下:
define(function (require, exports, module) {
var reqModule = require("./someModule");
requModule.test();
exports.asplode = function () {
//someing
}
});
CMD
CMD是SeaJS 在推廣過程中對模塊定義的規范化產出
CMD和AMD的區別有以下幾點:
1.對於依賴的模塊AMD是提前執行,CMD是延遲執行。不過RequireJS從2.0開始,也改成可以延遲執行(根據寫法不同,處理方式不通過)。
2.CMD推崇依賴就近,AMD推崇依賴前置。
//AMD
define(['./a','./b'], function (a, b) {
//依賴一開始就寫好
a.test();
b.test();
});
//CMD
define(function (requie, exports, module) {
//依賴可以就近書寫
var a = require('./a');
a.test();
...
//軟依賴
if (status) {
var b = requie('./b');
b.test();
}
});
雖然 AMD也支持CMD寫法,但依賴前置是官方文檔的默認模塊定義寫法。
3.AMD的api默認是一個當多個用,CMD嚴格的區分推崇職責單一。例如:AMD里require分全局的和局部的。CMD里面沒有全局的 require,提供 seajs.use()來實現模塊系統的加載啟動。CMD里每個API都簡單純粹。
requireJS主要解決兩個問題
1、多個js文件可能有依賴關系,被依賴的文件需要早於依賴它的文件加載到瀏覽器
2、js加載的時候瀏覽器會停止頁面渲染,加載文件越多,頁面失去響應時間越長