commonJS;AMD規(guī)范和CMD規(guī)范

1 個人理解;有錯希望大家指出;稍后更新拖拽上傳文件;

2奴烙、commonJS

commonjs的目標(biāo)是制定一個js模塊化的標(biāo)準(zhǔn),它的目標(biāo)制定一個可以同時在客服端和服務(wù)端運行的模塊独榴。這些模塊擁有自己獨立的作用域,也可以向頂層曝露出自己的api也就是module.exports柱彻。在ES6中common被制定為標(biāo)準(zhǔn)何之。但是在ES6還未被瀏覽器完美支持的情況下,commonjs規(guī)范之能在服務(wù)端發(fā)揮它的作用凭舶。比如在nodejs和webpack等中晌块。而我們服務(wù)端的異步加載模塊主要有2種加載方案,CMD和AMD帅霜,這兩種規(guī)范的典型是seajs和rjs(requirejs)匆背。這兩種方案雖然都是加載模塊的解決方案,但是還是有一些的差別身冀。

我們先來了解下commonjs規(guī)范钝尸。

此規(guī)范指出了如何編寫可以在同類模塊系統(tǒng)中所共用的模塊,這類模塊系統(tǒng)可以同時在客戶端和服務(wù)端搂根,以安全的或者不安全的方式已經(jīng)被實現(xiàn)了或者通過語法擴展可以被未來的系統(tǒng)所支持珍促。這些模塊需要提供頂級作用域的私有性,并提供從其他模塊導(dǎo)入單例對象到自身并且可以導(dǎo)出自身API的能力剩愧。含蓄的說猪叙,這個規(guī)范定義了如果一個模塊系統(tǒng)要支持共用模塊,那么它需要提供的最少的功能特性仁卷。

模塊上下文

在一個模塊中穴翩,存在一個自由的變量"require",它是一個函數(shù)锦积。

這個"require"函數(shù)接收一個模塊標(biāo)識符藏否。

"require"返回外部模塊所輸出的API。

如果出現(xiàn)依賴閉環(huán)(dependency cycle)充包,那么外部模塊在被它的傳遞依賴(transitive dependencies)所require的時候可能并沒有執(zhí)行完成副签;在這種情況下,"require"返回的對象必須至少包含此外部模塊在調(diào)用require函數(shù)(會進入當(dāng)前模塊執(zhí)行環(huán)境)之前就已經(jīng)準(zhǔn)備完畢的輸出基矮。

如果請求的模塊不能返回淆储,那么"require"必須拋出一個錯誤。

在一個模塊中家浇,會存在一個名為"exports"的自由變量本砰,它是一個對象,模塊可以在執(zhí)行的時候把自身的API加入到其中钢悲。

模塊必須使用"exports"對象來做為輸出的唯一表示点额。

如果不理解請移步CommonJS Modules/1.0 規(guī)范 & AMD 規(guī)范中文版這里面會有具體的例子舔株。

從模塊的上下文可以可以看出,這只是制定了一種模塊的方式还棱,在模塊內(nèi)部用require函數(shù)去獲取我們所需要的API载慈,用exports拋出當(dāng)前模塊的API。這其實也就是我們node的模塊方式珍手,沒錯办铡,node就是commonjs的實踐者,commonjs只是一種規(guī)范琳要,而nodejs就是實踐這個規(guī)范寡具。同樣的,ES6中稚补,也執(zhí)行了commonjs規(guī)范童叠,但是介于我們?yōu)g覽器還不能完美的支持ES6,所以我們也不能用這種很cool的方式课幕。(注解:當(dāng)然babel是一個完美的工具拯钻,把ES6轉(zhuǎn)成目前支持的es5。但是最終在瀏覽器中執(zhí)行的代碼還是es5撰豺。所以我們直接編寫的ES6代碼粪般,只能通過webpack等打包工具,把模塊之間的依賴通過打包工具來實現(xiàn)污桦。)

既然無法在瀏覽器中使用ES6亩歹,那么我們?nèi)绾驮跒g覽器中去執(zhí)行模塊依賴加載的呢?這里有2中方案去實現(xiàn)瀏覽器下模塊和依賴加載凡橱,CMD和AMD小作,這兩種方案的典型是seajs和requirejs。下面我們先分析AMD

3稼钩、AMD規(guī)范

AMD是為了彌補commonjs規(guī)范在瀏覽器中目前無法支持ES6的一種解決方案顾稀。異步模塊定義規(guī)范(AMD)制定了定義模塊的規(guī)則,這樣模塊和模塊的依賴可以被異步加載坝撑。這和瀏覽器的異步加載模塊的環(huán)境剛好適應(yīng)(瀏覽器同步加載模塊會導(dǎo)致性能静秆、可用性、調(diào)試和跨域訪問等問題)巡李。

這個規(guī)范只定義define函數(shù)抚笔。

define(id?侨拦,dependencies殊橙?,factory);

其中id和dependencies不是必須的膨蛮。

模塊的格式:

模塊名用來唯一標(biāo)識定義中模塊叠纹,它們同樣在依賴數(shù)組中使用。AMD的模塊名規(guī)范是CommonJS模塊名規(guī)范的超集敞葛。引用如下:

模塊名是由一個或多個單詞以正斜杠為分隔符拼接成的字符串

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

模塊名不允許文件擴展名的形式制肮,如".js"

模塊名可以為 "相對的" 或 "頂級的"冒窍。如果首字符為"."或".."則為"相對的"模塊名

頂級的模塊名從根命名空間的概念模塊解析

相對的模塊名從 "require" 書寫和調(diào)用的模塊解析

上文引用的CommonJS模塊id屬性常被用于JavaScript模塊递沪。

相對模塊名解析示例:

如果模塊 "a/b/c"請求"../d", 則解析為"a/d"

如果模塊 "a/b/c"請求"./e", 則解析為"a/b/e"

如果AMD的實現(xiàn)支持加載器插件(Loader-Plugins),則"!"符號用于分隔加載器插件模塊名和插件資源名豺鼻。由于插件資源名可以非常自由地命名,大多數(shù)字符都允許在插件資源名使用款慨。

define.amd (Object)用來標(biāo)識有amd模塊加載器的存在

例子:

  • 創(chuàng)建一個名為"alpha"的模塊儒飒,
    使用了require,exports檩奠,和名為"beta"的模塊: define("alpha", ["require", "exports", "beta"], function (require, exports, beta) { exports.verb = function { return beta.verb;
  • Or: return require("beta").verb; } }); //一個返回對象的匿名模塊: define(["alpha"], function (alpha) { return { verb: function{ return alpha.verb + 2; } }; }); //一個沒有依賴性的模塊可以直接定義對象: define({ add: function(x, y){ return x + y; } });
  • 一個使用了簡單CommonJS轉(zhuǎn)換的模塊定義: define(function (require, exports, module) { var a = require('a'), b = require('b'); exports.action = function {}; });

4桩了、AMD規(guī)范的實踐者requirejs

requirejs是AMD規(guī)范的實踐者,RequireJS 是一個JavaScript模塊加載器埠戳。它非常適合在瀏覽器中使用井誉,但它也可以用在其他腳本環(huán)境, 就像 Rhino and Node. 使用RequireJS加載模塊化腳本將提高代碼的加載速度和質(zhì)量。

在使用requirejs時整胃,可以查看官方文檔

requirejs非常簡單颗圣,我們只需要定義在頁面加載的時候,引入requirejs并且屁使,把mainjs指定在data-main中在岂,在mainjs中引入我們的requirejs.config和我們需要用到的頁面js,requirejs會根據(jù)我們的模塊去加載相應(yīng)的依賴蛮寂,然后執(zhí)行代碼蔽午。

// 頁面引入 // 模塊,這里使用AMD定義模塊的方式酬蹋,例如及老,定義一個模塊module1 define('module1', ['zepto'], function($) { console.log('this is module1') }) //mainjs內(nèi)容 require.config({ baseUrl: 'amdjs/modules', paths: { main: 'amdjs/main' zepto: 'http://zeptojs.com/zepto.min' }, shim: { }, waitSeconds: 15 }); // 你的模塊 requirejs(['module1'],function($) { console.log('load success!') })

config文件里面有許多參數(shù),這里我把常用的解釋下范抓,具體的請查看>requirejs文檔写半。
baseUrl:所有模塊的查找根路徑。
paths :path映射那些不直接放置于baseUrl下的模塊名尉咕。設(shè)置path時起始位置是相對于baseUrl的叠蝇,除非該path設(shè)置以"/"開頭或含有URL協(xié)議(如http:)。
shim: 為那些沒有使用define來聲明依賴關(guān)系、設(shè)置模塊的"瀏覽器全局變量注入"型腳本做依賴和導(dǎo)出配置悔捶。shim配置僅設(shè)置了代碼的依賴關(guān)系铃慷,想要實際加載shim指定的或涉及的模塊,仍然需要一個常規(guī)的require/define調(diào)用蜕该。設(shè)置shim本身不會觸發(fā)代碼的加載犁柜。
deps: 指定要加載的一個依賴數(shù)組。當(dāng)將require設(shè)置為一個config object在加載require.js之前使用時很有用堂淡。一旦require.js被定義馋缅,這些依賴就已加載。使用deps就像調(diào)用require([])绢淀,但它在loader處理配置完畢之后就立即生效萤悴。它并不阻塞其他的require調(diào)用,它僅是指定某些模塊作為config塊的一部分而異步加載的手段而已皆的。

cmd是commonjs另外的一種模塊加載方案覆履,這個規(guī)范本身偏向于commonjs的規(guī)范。他以一個文件就是一個模塊和ES6中標(biāo)準(zhǔn)的commonjs規(guī)范類似费薄。
它定義了以個define(factory)函數(shù)硝全。define接受factory參數(shù),factory可以是一個函數(shù)楞抡,也可以是一個對象或字符串伟众。
如果factory為函數(shù)時,它有三個參數(shù):require召廷,exports凳厢,module。
define.cmd是一個cmd模塊加載器的標(biāo)識

require方法:同步加載模塊
define(function(require, exports) {
// 獲取模塊 a 的接口
var a = require('./a');
// 調(diào)用模塊 a 的方法 a.doSomething;
});
require.async:用來在模塊的內(nèi)部異步加載模塊柱恤,并且完成后執(zhí)行指定回掉数初。
define(function(require, exports, module) { // 異步加載一個模塊,在加載完成時梗顺,執(zhí)行回調(diào) require.async('./b', function(b) { b.doSomething; }); // 異步加載多個模塊泡孩,在加載完成時,執(zhí)行回調(diào) require.async(['./c', './d'], function(c, d) { c.doSomething; d.doSomething; }); });

require.resolve:使用模塊系統(tǒng)內(nèi)部的路徑解析機制來解析并返回模塊路徑寺谤。該函數(shù)不會加載模塊仑鸥,只返回解析后的絕對路徑。

define(function(require, exports) { console.log(require.resolve('./b')); // ==> http://example.com/path/to/b.js });

exports:是一個對象变屁,用來向外提供模塊接口眼俊。
define(function(require) { // 通過 return 直接提供接口 return { foo: 'bar', doSomething: function {} }; });
module.exports:模塊暴露的出口
define(function(require, exports, module) { // 正確寫法 module.exports = { foo: 'bar', doSomething: function {} }; });

6、CMD規(guī)范的實踐者seaJS

seajs和requirejs的加載方式類似粟关,在頁面引入seajs文件后疮胖,加載seajs.config,并且之后加載mainjs。詳細(xì)信息請查看seajs文檔澎灸。

7院塞、CMD和AMD之間的差異

1)AMD(異步加載模塊),CMD(通用模塊)性昭,AMD是需要通過異步加載的形式把依賴加載進來拦止,然而CMD在require依賴的時候,可以通過同步的形式(require)糜颠,也可以通過異步的形式(require.async)汹族。當(dāng)然AMD也可以通過特殊的寫法支持CMD,但是不推崇其兴。

2)CMD 推崇依賴就近顶瞒,AMD 推崇依賴前置。在AMD中忌警,我們需要把依賴前置在依賴數(shù)組中搁拙。而在cmd中秒梳,我們只需要在使用這個模塊前法绵,把依賴的模塊require進來。

3)設(shè)計理念不一樣酪碘,在 SeaJS 里朋譬,API 的設(shè)計理念是:

保持簡單,職責(zé)單一兴垦。

遵守規(guī)范徙赢,但不拘泥。

適度靈活

requirejs中探越,require的用法多樣狡赐,比如:

require('a') -- gets exports of module a

require(['a']) -- fetch module a according to module name scheme

require(['a.js']) -- fetch a.js directly relative to current page

require({...}) -- set loader config

4)聚焦點有差異

seajs專注于瀏覽器環(huán)境下的模塊加載,而requirejs集成了在node環(huán)境以及Rhino 環(huán)境下的代碼钦幔,這導(dǎo)致requirejs比seajs更大枕屉。

參考文獻(xiàn):

注:本人見識短淺,有不夠準(zhǔn)確的地方萬望指正鲤氢。拜謝搀擂!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市卷玉,隨后出現(xiàn)的幾起案子哨颂,更是在濱河造成了極大的恐慌,老刑警劉巖相种,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件威恼,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機箫措,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門缭黔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蒂破,你說我怎么就攤上這事馏谨。” “怎么了附迷?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵惧互,是天一觀的道長。 經(jīng)常有香客問我喇伯,道長喊儡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任稻据,我火速辦了婚禮艾猜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捻悯。我一直安慰自己匆赃,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布今缚。 她就那樣靜靜地躺著算柳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪姓言。 梳的紋絲不亂的頭發(fā)上瞬项,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音何荚,去河邊找鬼囱淋。 笑死,一個胖子當(dāng)著我的面吹牛餐塘,可吹牛的內(nèi)容都是我干的妥衣。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼唠倦,長吁一口氣:“原來是場噩夢啊……” “哼称鳞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起稠鼻,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤冈止,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后候齿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體熙暴,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡闺属,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了周霉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掂器。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖俱箱,靈堂內(nèi)的尸體忽然破棺而出国瓮,到底是詐尸還是另有隱情,我是刑警寧澤狞谱,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布乃摹,位于F島的核電站,受9級特大地震影響跟衅,放射性物質(zhì)發(fā)生泄漏孵睬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一伶跷、第九天 我趴在偏房一處隱蔽的房頂上張望掰读。 院中可真熱鬧,春花似錦叭莫、人聲如沸蹈集。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽雾狈。三九已至廓潜,卻和暖如春抵皱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辩蛋。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工呻畸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人悼院。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓伤为,卻偏偏與公主長得像,于是被迫代替她去往敵國和親据途。 傳聞我的和親對象是個殘疾皇子绞愚,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容