|
你很喜歡Gmail和Trello之類的單頁面應(yīng)用,但是不太確定該從何開始。也許你的JavaScript代碼是如此的雜亂無章,以致于你很想在下一個(gè)項(xiàng)目上嘗試下JavaScript MVC庫和框架,卻苦于沒有頭緒?我正在撰寫一本單頁面應(yīng)用的書,所以我閱讀了大量網(wǎng)上的相關(guān)資料。在這里我嘗試提供一些看法,希望可以幫助你下決定。 簡(jiǎn)介這里討論的是時(shí)下最熱的框架,AngularJS、Backbone、Ember和Knockout。同時(shí)提到了Batman、CANjs、Meteor和Spine,但是沒有詳細(xì)展開。 我們從多個(gè)不同的角度考察每個(gè)項(xiàng)目,包括社區(qū)、領(lǐng)導(dǎo)、成熟度、大小、依賴、互操作性、啟發(fā)、理念和特性。 社區(qū)社區(qū)是一個(gè)衡量任何開源項(xiàng)目健康程度的重要指數(shù)。以下表格顯示了GitHub上每個(gè)項(xiàng)目的關(guān)注者數(shù)量。 你當(dāng)然不該僅僅根據(jù)這些數(shù)據(jù)做決定,但是它們確實(shí)為你提供了關(guān)于這些框架的一些感性認(rèn)識(shí): 最主流:
正在高速成長(zhǎng)的:
關(guān)注總量較低但是增長(zhǎng)迅猛的:
增長(zhǎng)性特別值得注意的是AngularJS 13個(gè)月以來的驚人增長(zhǎng)(379%)。在你做決定的時(shí)候要考慮上這一點(diǎn)。下面的圖表比較了13個(gè)月以來GitHub關(guān)注者的增長(zhǎng)速度,可以看出某個(gè)項(xiàng)目的社區(qū)成長(zhǎng)的速度??紤]到原先的社區(qū)大小,Meteor(130%)、Ember(104%)、Knockout(76%)和Backbone(64%)的增長(zhǎng)速度也很驚人。 領(lǐng)導(dǎo)了解項(xiàng)目的核心開發(fā)者的背景,他們創(chuàng)建框架時(shí)嘗試解決的問題,有助于你欣賞他們?cè)谠O(shè)計(jì)上的決策和動(dòng)機(jī)。例如,David Heinemeier Hansson,流行的Ruby on Rails框架的締造者,是37signals的簽約開發(fā)者,從事項(xiàng)目設(shè)計(jì),每周只有10小時(shí)能花在開發(fā)框架上。Ruby on Rails事實(shí)上是從他和37signals的簽約工作中提取出來的。這一背景有助于你理解為什么這個(gè)框架需要將開發(fā)效率提升到極限——這意味這使用大量的約定(已經(jīng)做出的決定)和支架程序(生成的代碼)。下面,我將介紹JavaScript MVC 框架的締造者,也許也能激起你對(duì)他們的工作的欣賞。 BackboneJeremy Ashkenas和DocumentCloud Jeremy Ashkenas是CoffeeScript編程語言、Backbone.js JavaScript框架和Underscore.js JavaScript工具庫的創(chuàng)立者。根據(jù)維基百科,他現(xiàn)在在NYTimes/DocumentCloud從事互動(dòng)新聞方面的開發(fā)。 圖片來自The Canadian University Software Engineering Conference。 AngularJSAngularJS最初由Google的Mi?ko Hevery和Adam Abrons于2009年開發(fā),當(dāng)時(shí)是一個(gè)在線JSON存儲(chǔ)服務(wù)的一部分。Abrons后來離開了這個(gè)項(xiàng)目,但是在Google工作的Hevery繼續(xù)開發(fā),和Google的員工Igor Minár、Vojta Jína一起維護(hù)這個(gè)庫。 圖片來自Devoxx 2012 KnockoutSteve Sanderson是Knockout的原作者。Steve Sanderson現(xiàn)在為微軟工作,他所在的團(tuán)隊(duì)開發(fā)ASP.NET、IIS和其他web項(xiàng)目。他以前以外包開發(fā)者或顧問身份為Bristol周邊的客戶開發(fā).NET下的軟件,他還為Apress寫了一些書,包括《Pro ASP.NET MVC框架》。 EmberEmber核心成員中最知名的公眾人物是Yehuda Katz和Tom Dale。 Yehuda Katz是Ember.js、Ruby on Rails和jQuery的核心開發(fā)者,他白天的時(shí)間花在他創(chuàng)辦的創(chuàng)業(yè)公司,Tilde Inc.。Yehuda是暢銷書《jQuery in Action》和《Rails 3 in Action》的作者之一。 Tom Dale原先在SproutCore團(tuán)隊(duì)工作。他以前是蘋果軟件工程師,在開發(fā)MobileMe和iCloud應(yīng)用時(shí)精通了前端JavaScript技能。
圖片來自Ember Team MeteorMeteor的開發(fā)團(tuán)隊(duì)剛剛得到了1.12千萬美金,所以他們可以全職開發(fā)。他們的團(tuán)隊(duì)有12名開發(fā)者,每個(gè)開發(fā)者的簡(jiǎn)歷都讓人印象深刻。這個(gè)團(tuán)隊(duì)擁有雄心勃勃的計(jì)劃,超越了大多數(shù)專注于組織客戶端代碼和狀態(tài)的JavaScript MVC框架。Meteor是一個(gè)全端框架,包括服務(wù)器架構(gòu)和數(shù)據(jù)庫。 成熟度評(píng)估框架的成熟度可以幫助你理解在項(xiàng)目中使用新技術(shù)的風(fēng)險(xiǎn)。未經(jīng)考驗(yàn)的新框架在文檔、擴(kuò)展性、穩(wěn)定性(API改變)和支持(尋找了解該框架的開發(fā)者來維護(hù)代碼)方面可能存在問題,這些問題可能導(dǎo)致出乎意料的結(jié)果,即使從其他方面看起來決策很明智。需要考慮的項(xiàng)目包括:多少生產(chǎn)環(huán)境下的應(yīng)用使用這些框架?這些應(yīng)用有多少用戶?文檔是否良好?例子和教程是否充足?例子是否過時(shí)?API是否穩(wěn)定?其他開發(fā)者了解或正打算了解這門技術(shù)么?
大小了解每個(gè)框架的大小,它會(huì)在你的應(yīng)用中增加多少分量是很重要的。大小會(huì)影響性能,不過它同時(shí)也會(huì)暗示你這個(gè)框架的雄心有多大,你學(xué)習(xí)它可能需要花多少時(shí)間,以及它提供多少幫助你構(gòu)建應(yīng)用的方式(即特性和魯棒性)。一個(gè)框架的野心越大,特性越多,通常也就意味更難在應(yīng)用的頁面上將它與其他部件組合。輕量的框架更像一個(gè)庫,將他集成到你的項(xiàng)目中所耗費(fèi)的精力也相對(duì)較小。 包括Backbone和Spine在內(nèi)的一些項(xiàng)目為自己的輕量而自豪,這些項(xiàng)目更多地將自己視作庫,而不是框架。通常這些小型的框架留下了空間,你可以使用你自己的庫來實(shí)現(xiàn)特定功能,例如模板和路由。我在討論這些框架的特性的時(shí)候?qū)⒗^續(xù)討論這個(gè)話題。 包括Ember和AngularJS在內(nèi)的其他項(xiàng)目雄心勃勃,更適合叫做框架。它們通常擁有更多內(nèi)建的特性,更少依賴外部庫。 下面的列表顯示了我更傾向于將哪些項(xiàng)目歸入庫或框架:
依賴性使用這些項(xiàng)目構(gòu)建真實(shí)世界的應(yīng)用的時(shí)候還需要哪些庫?以下的圖表展示了為了保證開發(fā)效率每個(gè)庫所需的依賴,以及這些依賴的大小。 通過從cdnjs下載庫,我們收集了這些數(shù)據(jù)。在實(shí)踐中,大多數(shù)的項(xiàng)目會(huì)使用jQuery配合這些框架處理DOM,因?yàn)樾枰獎(jiǎng)赢嫼虯JAX。在移動(dòng)應(yīng)用中,使用Zepto.js來代替jQuery處理DOM不是什么稀奇的事。Zepto.js是一個(gè)比jQuery輕量得多的庫。雖然Zepto.js不支持Internet Explorer,但是移動(dòng)應(yīng)用通常不需要為此操心。AngularJS包含了一個(gè)jQuery 的縮減版jQLite。但是如果你在項(xiàng)目中使用了jQuery的話,它會(huì)被覆蓋。AngularJS團(tuán)隊(duì)鼓勵(lì)開發(fā)者,如非必要,不要添加完整的jQuery庫。為了幫助你做出正確的選擇,下面的表格同時(shí)顯示了移動(dòng)版(假定使用Zepto.js)和web版(假定使用jQuery)。
互操作性這一部分討論是否框架設(shè)計(jì)為控制整個(gè)頁面或者它可以被用于現(xiàn)存頁面的一個(gè)部分——你可能想漸漸將新技術(shù)引入現(xiàn)有的項(xiàng)目。前面的庫和框架的討論基本可以體現(xiàn)每個(gè)項(xiàng)目的互操作性,庫更傾向于很容易地集成到現(xiàn)存的項(xiàng)目,而框架為你做更多的事,但是不容易和其他項(xiàng)目配合。 AngularJSAngularJS可以和其他庫很好地配合,但是它鼓勵(lì)開發(fā)者們考慮是否可以不用jQuery和jQueryUI.事實(shí)上Angular內(nèi)置了一個(gè)jQuery的子集jqLite。遵循這一實(shí)踐的理由是讓單元測(cè)試更容易,因?yàn)楹芏嘁蕾噹旌筒寮O(shè)計(jì)的時(shí)候沒有考慮單元測(cè)試,相應(yīng)地更難和單元測(cè)試配合。在實(shí)踐中,大多數(shù)的開發(fā)者最終還是因?yàn)槟承┨匦允褂昧薺Query. Backbone由于Backbone的小尺寸和無預(yù)設(shè)的架構(gòu),將其包含在眾多流行的客戶端庫和服務(wù)器端技術(shù)中很容易。 Ember.js被設(shè)計(jì)為在運(yùn)行時(shí)控制整個(gè)頁面,所以不太適合用于頁面的部分。 Knockout.js可以在項(xiàng)目中作為小組件使用,不控制整個(gè)頁面。 啟發(fā)記者采訪音樂家時(shí)最愛問的問題是“你在成長(zhǎng)的時(shí)候聽哪些藝術(shù)家的音樂,或者說,誰啟發(fā)了你?”這個(gè)問題常常使得讀者能夠預(yù)期音樂家的聲樂。這些框架中大部分的觀念都不是全新的,而是來自于創(chuàng)造者以前工作的項(xiàng)目中喜歡的部分。這一部分總結(jié)了我從框架創(chuàng)造者的訪談中收集到的關(guān)于啟發(fā)的信息。 AngularJSHTML類的聲明性的語言,Adobe和Flex、微軟的WPF\Silverligt等RIA技術(shù)給AngularJS的影響很深。這些聲明性技術(shù)沒有”主體“方法,僅僅表達(dá)需要發(fā)生什么,而不指定具體實(shí)現(xiàn)。視圖和模型中的數(shù)據(jù)雙向綁定是這一聲明式編程風(fēng)格在絕佳例子。此外,在Google的服務(wù)器端Java代碼中大量使用的依賴注入和IOC容器(特別是Juice)也啟發(fā)了AngularJS的創(chuàng)造者。他們重視單元測(cè)試,需要框架被設(shè)計(jì)允許依賴注入,這樣測(cè)試就可以從其他應(yīng)用層剝離出來,運(yùn)行起來也會(huì)更快。 EmberTom Dale在Quora上談了Ember受到的影響:
此外,Ember.js是SproutCore JavaScript庫的進(jìn)化版,SproutCore停止仿效Cocoa而更多地借鑒jQuery的時(shí)候,Ember誕生了,理解這一點(diǎn)很重要。 Knockouthanselminutes的播客提供了Steve Sanderson受到哪些方面啟發(fā)的背景信息。總結(jié)一下,MVVM設(shè)計(jì)模式和微軟的WPF、Sliverlight等聲明性技術(shù)是最大的啟發(fā)者。你可能會(huì)發(fā)現(xiàn)Knockout的最佳特性——聲明性的數(shù)據(jù)雙向綁定——和Anjular相似,因?yàn)閮烧叩膯l(fā)者是相似的。 理念報(bào)紙?jiān)趫?bào)道新聞的時(shí)候努力保持中立。唯一的例外是編者案,鼓勵(lì)表達(dá)觀點(diǎn),作者通常在問題上占據(jù)一個(gè)強(qiáng)烈的立場(chǎng)。但是大多數(shù)情況,這兩者既不是嚴(yán)格的中立報(bào)道,也不是強(qiáng)烈的意見表達(dá),而是位于兩者之間的連續(xù)統(tǒng)。技術(shù)框架也有類似的劃分,即是否強(qiáng)主張。例如,Ruby on Rails推崇約定優(yōu)于配置,并且為開發(fā)者做了大量決定,包括文件結(jié)構(gòu)和數(shù)據(jù)訪問。相應(yīng)地,它被認(rèn)為是強(qiáng)主張的。其他Sinatra類的服務(wù)器端框架更輕量,并不預(yù)設(shè)文件結(jié)構(gòu)和數(shù)據(jù)訪問。相應(yīng)的,被看成是無主張的。服務(wù)端框架有理念,客戶端JavaScript MVC框架同樣有,我們討論的框架也可以被置于強(qiáng)主張和無主張的連續(xù)統(tǒng)中考察。讓我們看看每個(gè)項(xiàng)目,然后討論他們的理念。 Backbone: 無主張Backbone是最開明的框架,極度無主張,允許開發(fā)者做出自己的決定,有時(shí)這會(huì)導(dǎo)致代碼差異過大而難以維護(hù)。唯一的例外是Backbone假定服務(wù)器端有一個(gè)REST服務(wù),我會(huì)在特性部分詳細(xì)討論這一點(diǎn)。這一假定可以通過覆蓋模型的sync方法來繞過。 AngularJS: 強(qiáng)主張AngularJS有較強(qiáng)的主張,特別是它強(qiáng)調(diào)可測(cè)試性和依賴注入。此外,HTML類的聲明性編程很棒的理念也在框架中廣泛體現(xiàn)。 Ember: 極度強(qiáng)主張Ember力求開發(fā)者僅對(duì)應(yīng)用的特有部分作決定,其余全部交給約定和支架。這個(gè)理念和Ruby on Rails和jQuery很接近。這一理念最好的表達(dá)出現(xiàn)在的網(wǎng)站上:
Ember標(biāo)準(zhǔn)化了文件和url結(jié)構(gòu),當(dāng)然,有必要的時(shí)候也允許你覆蓋這些設(shè)定。你可以預(yù)期的是大量的代碼會(huì)為你生成,大量的類似文件結(jié)構(gòu)的約定。相應(yīng)地,你需要做出的常規(guī)選擇更少,因?yàn)榭蚣芤呀?jīng)為你選定了合理的默認(rèn)值,你可以著手構(gòu)建你的應(yīng)用的特殊部分。 Knockout: 無主張路由和數(shù)據(jù)存儲(chǔ)留給開發(fā)者決定。不預(yù)設(shè)文件或URL結(jié)構(gòu)。甚至允許用基于字符串的模板替換聲明性的基于DOM的模板。 特性我們可以將這些JavaScript MVC框架看成是幫助開發(fā)者構(gòu)建單頁應(yīng)用的常用特性集合。每個(gè)框架實(shí)現(xiàn)這些特性的方式,或者不實(shí)現(xiàn)這些特性的方式(通過其他庫來補(bǔ)全框架的功能)是值得留心的。 JavaScript MVC框架的主要特性是什么?
除此以外,一些框架提供常用的語言層面的服務(wù),例如通用的pub/sub事件模型和面向?qū)ο蟮睦^承支持。 數(shù)據(jù)綁定這是最受吹捧的特性。你通過HTML input修改了數(shù)據(jù),綁定到input的JavaScript對(duì)象馬上更新,其他綁定的用戶接口元素也隨之更新。在很多框架中,反之亦然。如果你修改了JavaScript對(duì)象,html會(huì)自動(dòng)刷新。這是一個(gè)web上的雙向的數(shù)據(jù)綁定,我們?cè)贔lex、Windows Forms、WPF等富客戶端應(yīng)用框架中見過這類綁定。以下的表格顯示了哪些框架支持?jǐn)?shù)據(jù)綁定。
有些人可能持有異議,因?yàn)锽ackbone和Spine部分支持?jǐn)?shù)據(jù)綁定。但是我覺得大量工作需要留給開發(fā)者,保險(xiǎn)起見,不如說這些庫不支持這些特性。 視圖模板客戶端的JavaScript數(shù)據(jù)模型需要穿插在HTML中,這些框架采用兩種方式解決問題。 基于字符串的模板(目前最流行的是handlebars.js),將字符串、文本模板中的動(dòng)態(tài)部分替換為模型中的數(shù)據(jù)。字符串常被提到也飽受爭(zhēng)議的特性之一是性能。其缺點(diǎn)是調(diào)試控制語句類的邏輯很困難。 基于DOM的模板擁抱標(biāo)記語言的聲明式本性,這是開了掛的html,通過html中的附加屬性來描述需要的綁定和事件。這些庫需要的代碼大大減少,為開發(fā)者做了很多事情。
模型(可觀察的:跟蹤改動(dòng))一些框架(Backbone、Spine)更專注于模型,要求開發(fā)者在base模型的基礎(chǔ)上擴(kuò)展JavaScript類,通過 其他庫(AngularJS)對(duì)頁面上的所有綁定的DOM元素作臟檢查,因?yàn)闆]有標(biāo)準(zhǔn)的get和set訪問器。因此將這些庫用于大頁面時(shí)將導(dǎo)致性能問題。這些庫不僅需要更少的刷新模板的代碼,也不需要你使用特定的get和set訪問器來修改模型中的數(shù)據(jù),所以你可以使用原始的JavaScript對(duì)象。這大大提升了開發(fā)效率,這一點(diǎn)在框架的初學(xué)者身上體現(xiàn)得尤為明顯。 數(shù)據(jù)存儲(chǔ)這些框架通過以下方式將數(shù)據(jù)存儲(chǔ)到服務(wù)器
REST一些框架默認(rèn)預(yù)設(shè)后端有非常整潔的REST JSON服務(wù),并且,至少在默認(rèn)的情況下,前端與后端頻繁交互,在后臺(tái)異步更新數(shù)據(jù),而用戶界面響應(yīng)流暢。這些框架內(nèi)部使用jQuery或Zepto發(fā)送合適的AJAX請(qǐng)求給服務(wù)器。用戶界面的HTML DOM元素監(jiān)聽?wèi)?yīng)用的JavaScript對(duì)象模型的改動(dòng),同步機(jī)制得到模型屬性的更改提醒,將改動(dòng)發(fā)送給REST服務(wù),確保模型和服務(wù)器同步。 在線和離線Backbone默認(rèn)在客戶端保存數(shù)據(jù)之前發(fā)送請(qǐng)求,這樣服務(wù)器端和客戶端同步就很容易。和Backbone非常類似的Spine框架,采用了不同的方式,在異步發(fā)送請(qǐng)求到服務(wù)器前,先在客戶端存儲(chǔ)記錄,這提供了更好的用戶界面響應(yīng),在移動(dòng)應(yīng)用中常發(fā)生的離線狀態(tài)下也能工作。如果你的項(xiàng)目需要支持離線,需要了解清楚框架對(duì)該特性的支持 DIY這些框架要求開發(fā)者使用 數(shù)據(jù)存儲(chǔ)特性Meteor之類精心制作的框架擁有更完整的數(shù)據(jù)存儲(chǔ)方案,但是要求服務(wù)器端有MongoDB數(shù)據(jù)庫。這類方案試圖提供一個(gè)擴(kuò)展性優(yōu)異的默認(rèn)解決方案,提供從頭到尾的JavaScript開發(fā)體驗(yàn)。 以下的表格總結(jié)了每個(gè)框架是如何處理數(shù)據(jù)存儲(chǔ)的。
路由將URL路由映射到JavaScript函數(shù),可以支持瀏覽器的后退按鈕。單頁應(yīng)用最大的缺點(diǎn)之一是由于頁面無刷新,瀏覽器歷史不會(huì)添加條目,所以后退按鈕通常無法將用戶帶回頁面的前一狀態(tài),除非開發(fā)者在主要的狀態(tài)改變時(shí)做一些額外的工作,通過在URL后附加井號(hào),或者,使用現(xiàn)代瀏覽器的push和pop狀態(tài),實(shí)現(xiàn)狀態(tài)跟蹤機(jī)制。總之,大多數(shù)項(xiàng)目都提供基本、初步而有用的功能。Knockout的做法很簡(jiǎn)單,允許你使用其他的第三方開源庫。
蘋果對(duì)蘋果考察各個(gè)框架的特性之后,我發(fā)現(xiàn)我并不是在做一個(gè)“蘋果對(duì)蘋果”的比較。一個(gè)更為公平的比較也許是將AngularJS和EmberJS之類全面的框架與配合第三方庫使用的Backbone和KnockoutJS之類的MV*框架進(jìn)行比較。具體來說,下面的比較會(huì)更有意義:
以后的博客中我會(huì)繼續(xù)深入。 告訴我更多為項(xiàng)目選擇JavaScript MVC框架時(shí)有大量需要考慮的事項(xiàng),我希望本文是一個(gè)良好的開始。請(qǐng)?jiān)谠u(píng)論中分享你使用這些框架的體驗(yàn),包括它們的優(yōu)異之處,也包括它們使用上的陷阱。 |
|
|