javascript AMD

  1. AMD的由來

前端技術(shù)雖然在不斷發(fā)展之中施敢,卻一直沒有質(zhì)的飛躍狭莱。除了已有的各大著名框架,比如Dojo,JQuery仆嗦,ExtJs等等,很多公司也都有著自己的前端開發(fā)框架谆甜。這些框架的使用效率以及開發(fā)質(zhì)量在很大程度上都取決于開發(fā)者對其的熟悉程度集绰,以及對JavaScript的熟悉程度,這也是為什么很多公司的技術(shù)帶頭人都喜歡開發(fā)一個自己的框架罕袋。開發(fā)一個自己會用的框架并不難碍岔,但開發(fā)一個大家都喜歡的框架卻很難。從一個框架遷移到一個新的框架榆纽,開發(fā)者很有可能還會按照原有框架的思維去思考和解決問題捏肢。這其中的一個重要原因就是JavaScript本身的靈活性:框架沒辦法絕對的約束你的行為,一件事情總可以用多種途徑去實現(xiàn)衣屏,所以我們只能在方法學上去引導正確的實施方法辩棒。慶幸的是煮甥,在這個層面上的軟件方法學研究成肘,一直有人在去不斷的嘗試和改進斧蜕,CommonJS就是其中的一個重要組織。他們提出了許多新的JavaScript架構(gòu)方案和標準洒闸,希望能為前端開發(fā)提供銀彈均芽,提供統(tǒng)一的指引。

AMD規(guī)范就是其中比較著名一個深纲,全稱是Asynchronous Module Definition劲妙,即異步模塊加載機制。從它的規(guī)范描述頁面看币呵,AMD很短也很簡單侨颈,但它卻完整描述了模塊的定義,依賴關(guān)系哈垢,引用關(guān)系以及加載機制温赔。從它被requireJS,NodeJs陶贼,Dojo,JQuery使用也可以看出它具有很大的價值痹屹,沒錯枉氮,JQuery近期也采用了AMD規(guī)范暖庄。在這篇文章中培廓,我們就將介紹AMD的性質(zhì)春叫,用法,優(yōu)勢以及應用場景价匠。從AMD中我們也能學習到如何在更高層面去設計自己的前端應用呛每。

  1. AMD是什么

作為一個規(guī)范,只需定義其語法API洋腮,而不關(guān)心其實現(xiàn)颓遏。AMD規(guī)范簡單到只有一個API滞时,即define函數(shù):

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

其中:

module-name: 模塊標識,可以省略曼玩。

array-of-dependencies: 所依賴的模塊窒百,可以省略。

module-factory-or-object: 模塊的實現(xiàn)顷帖,或者一個JavaScript對象渤滞。

從中可以看到,第一個參數(shù)和第二個參數(shù)都是可以省略的陶舞,第三個參數(shù)則是模塊的具體實現(xiàn)本身绪励。后面將介紹在不同的應用場景下唠粥,他們會使用不同的參數(shù)組合晤愧。

從這個define函數(shù)AMD中的A:Asynchronous雅宾,我們也不難想到define函數(shù)具有的另外一個性質(zhì),異步性贯吓。當define函數(shù)執(zhí)行時蜀变,它首先會異步的去調(diào)用第二個參數(shù)中列出的依賴模塊,當所有的模塊被載入完成之后库北,如果第三個參數(shù)是一個回調(diào)函數(shù)則執(zhí)行寒瓦,然后告訴系統(tǒng)模塊可用,也就通知了依賴于自己的模塊自己已經(jīng)可用杂腰。如果對應到dojo1.6之前的實現(xiàn),那么在功能上可以有如下對應關(guān)系:

module-name: dojo.provide

dependencies: dojo.require

module-factory: dojo.declare

不同的是惜颇,在加載依賴項時少辣,AMD用的是異步,而dojo.require是同步锨亏。異步和同步的區(qū)別顯而易見忙干,前者不會阻塞瀏覽器,有更好的性能和靈活性劣摇。而對于NodeJs這樣的服務器端AMD弓乙,則模塊載入無需阻塞服務器進程钧惧,同樣提高了性能浓瞪。

  1. AMD實例:如何定義一個模塊

下面代碼定義了一個alpha模塊巧婶,并且依賴于內(nèi)置的require,exports模塊英岭,以及外部的beta模塊湿右。可以看到吭狡,第三個參數(shù)是回調(diào)函數(shù)丈莺,可以直接使用依賴的模塊,他們按依賴聲明順序作為參數(shù)提供給回調(diào)函數(shù)弛秋。

這里的require函數(shù)讓你能夠隨時去依賴一個模塊牵现,即取得模塊的引用邀桑,從而即使模塊沒有作為參數(shù)定義,也能夠被使用壁畸;exports是定義的alpha 模塊的實體,在其上定義的任何屬性和方法也就是alpha模塊的屬性和方法太抓。通過exports.verb = ...就是為alpha模塊定義了一個verb方法令杈。例子中是簡單調(diào)用了模塊beta的verb方法。

define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {

exports.verb = function() {

return beta.verb();

//或者:

return require("beta").verb();

}

});

  1. 匿名模塊

define 方法允許你省略第一個參數(shù)掉丽,這樣就定義了一個匿名模塊,這時候模塊文件的文件名就是模塊標識捶障。如果這個模塊文件放在a.js中,那么a就是模塊名担平《Р浚可以在依賴項中用"a"來依賴于這個匿名模塊。這帶來一個好處空另,就是模塊是高度可重用的蹋砚。你拿來一個匿名模塊,隨便放在一個位置就可以使用它循榆,模塊名就是它的文件路徑墨坚。這也很好的符合了DRY(Don't Repeat Yourself)原則。

下面的代碼就定義了一個依賴于alpha模塊的匿名模塊:

define(["alpha"], function (alpha) {

return {

verb: function(){

return alpha.verb() + 2;

}

};

});

  1. 僅有一個參數(shù)的define

前面提到盗尸,define的前兩個參數(shù)都是可以省略的帽撑。第三個參數(shù)有兩種情況,一種是一個JavaScript對象扣蜻,另一種是一個函數(shù)及塘。

如果是一個對象,那么它可能是一個包含方法具有功能的一個對象芳肌;也有可能是僅提供數(shù)據(jù)。后者和JSON-P非常類似檬嘀,因此AMD也可以認為包含了一個完整的 JSON-P實現(xiàn)责嚷。模塊演變?yōu)橐粋€簡單的數(shù)據(jù)對象,這樣的數(shù)據(jù)對象是高度可用的罕拂,而且因為是靜態(tài)對象,它也是CDN友好的衷掷,可以提高JSON-P的性能柿菩。考慮一個提供中國省市對應關(guān)系的JavaScript對象懦胞,如果以傳統(tǒng)JSON-P的形式提供給客戶端凉泄,它必須提供一個callback函數(shù)名,根據(jù)這個函數(shù)名動態(tài)生成返回數(shù)據(jù)胀糜,這使得標準JSON-P數(shù)據(jù)一定不是CDN友好的蒂誉。但如果用AMD,這個數(shù)據(jù)文件就是如下的形式:

define({

provinces: [

{

name: '上海',

areas: ['浦東新區(qū)', '徐匯區(qū)']},

{

name: '江蘇',

cities: ['南京', '南通']}

//.....

]

});

假設這個文件名為china.js括堤,那么如果某個模塊需要這個數(shù)據(jù)陡蝇,只需要:

define(['china', function(china){

//在這里使用中國省市數(shù)據(jù)

});

通過這種方式哮肚,這個模塊是真正高度可復用的,無論是用遠程的恼策,還是Copy到本地項目,都節(jié)約了開發(fā)時間和維護時間分唾。

如果參數(shù)是一個函數(shù)狮斗,其用途之一是快速開發(fā)實現(xiàn)。適用于較小型的應用折砸,你無需提前關(guān)注自己需要什么模塊沙峻,自己給誰用。在函數(shù)中摔寨,可以隨時require自己需要的模塊。例如:

define(function(){

var p = require('china');

//使用china這個模塊

});

即你省略了模塊名删顶,以及自己需要依賴的模塊淑廊。這不意味著你無需依賴于其他模塊,而是可以讓你在需要的時候去require這些模塊猎荠。define方法在執(zhí)行的時候蜀备,會調(diào)用函數(shù)的toString方法,并掃描其中的require調(diào)用输虱,提前幫助你載入這些模塊脂凶,載入完成之后再執(zhí)行。這使得快速開發(fā)成為可能亭病。需要注意的一點是嘶居,Opera不能很好的支持函數(shù)的toString方法,因此,在瀏覽器中它的適用性并不是很強菠齿。但如果你是通過build工具打包所有的 JavaScript文件坐昙,這將不是問題,構(gòu)建工具會幫助你掃描require并強制載入依賴的模塊襟士。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末陋桂,一起剝皮案震驚了整個濱河市蝶溶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌抖所,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件暴匠,死亡現(xiàn)場離奇詭異每窖,居然都是意外死亡弦悉,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門瀑志,熙熙樓的掌柜王于貴愁眉苦臉地迎上來污秆,“玉大人,你說我怎么就攤上這事战得〗龋” “怎么了痛黎?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長掖蛤。 經(jīng)常有香客問我,道長蚓庭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任垢袱,我火速辦了婚禮请契,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘爽锥。我一直安慰自己畔柔,他們只是感情好,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布腮考。 她就那樣靜靜地躺著玄捕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪寂纪。 梳的紋絲不亂的頭發(fā)上赌结,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音拟杉,去河邊找鬼量承。 笑死穴店,一個胖子當著我的面吹牛拿穴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播球凰,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼呕诉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了甩挫?” 一聲冷哼從身側(cè)響起椿每,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤拖刃,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后兑牡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡亿虽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年洛勉,在試婚紗的時候發(fā)現(xiàn)自己被綠了如迟。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡此再,死狀恐怖玲销,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情贤斜,我是刑警寧澤逛裤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布带族,位于F島的核電站洽糟,受9級特大地震影響堕战,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嘱丢,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望汁政。 院中可真熱鬧缀旁,春花似錦、人聲如沸并巍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽剃执。三九已至,卻和暖如春肾档,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背俗慈。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工速种, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人馏颂。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像救拉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子亿絮,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

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