你很喜歡Gmail和Trello之類的單頁面應用,可是不太肯定該從何開始。也許你的JavaScript代碼是如此的雜亂無章,以至於你很想在下一個項目上嘗試下JavaScript MVC庫和框架,卻苦於沒有頭緒?我正在撰寫一本單頁面應用的書,因此我閱讀了大量網上的相關資料。在這裏我嘗試提供一些見解,但願能夠幫助你下決定。javascript
這裏討論的是時下最熱的框架,AngularJS、Backbone、Ember和Knockout。同時提到了Batman、CANjs、Meteor和Spine,可是沒有詳細展開。html
咱們從多個不一樣的角度考察每一個項目,包括社區、領導、成熟度、大小、依賴、互操做性、啓發、理念和特性。前端
社區是一個衡量任何開源項目健康程度的重要指數。如下表格顯示了GitHub上每一個項目的關注者數量。java
你固然不應僅僅根據這些數據作決定,可是它們確實爲你提供了關於這些框架的一些感性認識:web
最主流:ajax
正在高速成長的:數據庫
關注總量較低可是增加迅猛的:編程
特別值得注意的是AngularJS 13個月以來的驚人增加(379%)。在你作決定的時候要考慮上這一點。下面的圖表比較了13個月以來GitHub關注者的增加速度,能夠看出某個項目的社區成長的速度。考慮到原先的社區大小,Meteor(130%)、Ember(104%)、Knockout(76%)和Backbone(64%)的增加速度也很驚人。json
瞭解項目的核心開發者的背景,他們建立框架時嘗試解決的問題,有助於你欣賞他們在設計上的決策和動機。例如,David Heinemeier Hansson,流行的Ruby on Rails框架的締造者,是37signals的簽約開發者,從事項目設計,每週只有10小時能花在開發框架上。Ruby on Rails事實上是從他和37signals的簽約工做中提取出來的。這一背景有助於你理解爲何這個框架須要將開發效率提高到極限——這意味這使用大量的約定(已經作出的決定)和支架程序(生成的代碼)。下面,我將介紹JavaScript MVC 框架的締造者,也許也能激起你對他們的工做的欣賞。segmentfault
Jeremy Ashkenas和DocumentCloud
Jeremy Ashkenas是CoffeeScript編程語言、Backbone.js JavaScript框架和Underscore.js JavaScript工具庫的創立者。根據維基百科,他如今在NYTimes/DocumentCloud從事互動新聞方面的開發。
圖片來自The Canadian University Software Engineering Conference。
AngularJS最初由Google的Miško Hevery和Adam Abrons於2009年開發,當時是一個在線JSON存儲服務的一部分。Abrons後來離開了這個項目,可是在Google工做的Hevery繼續開發,和Google的員工Igor Minár、Vojta Jína一塊兒維護這個庫。
圖片來自Devoxx 2012
Steve Sanderson是Knockout的原做者。Steve Sanderson如今爲微軟工做,他所在的團隊開發ASP.NET、IIS和其餘web項目。他之前之外包開發者或顧問身份爲Bristol周邊的客戶開發.NET下的軟件,他還爲Apress寫了一些書,包括《Pro ASP.NET MVC框架》。
Ember核心成員中最知名的公衆人物是Yehuda Katz和Tom Dale。
Yehuda Katz是Ember.js、Ruby on Rails和jQuery的核心開發者,他白天的時間花在他創辦的創業公司,Tilde Inc.。Yehuda是暢銷書《jQuery in Action》和《Rails 3 in Action》的做者之一。
Tom Dale原先在SproutCore團隊工做。他之前是蘋果軟件工程師,在開發MobileMe和iCloud應用時精通了前端JavaScript技能。
圖片來自Ember Team
Meteor的開發團隊剛剛獲得了1.12千萬美金,因此他們能夠全職開發。他們的團隊有12名開發者,每一個開發者的簡歷都讓人印象深入。這個團隊擁有雄心勃勃的計劃,超越了大多數專一於組織客戶端代碼和狀態的JavaScript MVC框架。Meteor是一個全端框架,包括服務器架構和數據庫。
評估框架的成熟度能夠幫助你理解在項目中使用新技術的風險。未經考驗的新框架在文檔、擴展性、穩定性(API改變)和支持(尋找了解該框架的開發者來維護代碼)方面可能存在問題,這些問題可能致使出乎意料的結果,即便從其餘方面看起來決策很明智。須要考慮的項目包括:多少生產環境下的應用使用這些框架?這些應用有多少用戶?文檔是否良好?例子和教程是否充足?例子是否過期?API是否穩定?其餘開發者瞭解或正打算了解這門技術麼?
瞭解每一個框架的大小,它會在你的應用中增長多少份量是很重要的。大小會影響性能,不過它同時也會暗示你這個框架的雄心有多大,你學習它可能須要花多少時間,以及它提供多少幫助你構建應用的方式(即特性和魯棒性)。一個框架的野心越大,特性越多,一般也就意味更難在應用的頁面上將它與其餘部件組合。輕量的框架更像一個庫,將他集成到你的項目中所耗費的精力也相對較小。
包括Backbone和Spine在內的一些項目爲本身的輕量而自豪,這些項目更多地將本身視做庫,而不是框架。一般這些小型的框架留下了空間,你可使用你本身的庫來實現特定功能,例如模板和路由。我在討論這些框架的特性的時候將繼續討論這個話題。
包括Ember和AngularJS在內的其餘項目雄心勃勃,更適合叫作框架。它們一般擁有更多內建的特性,更少依賴外部庫。
下面的列表顯示了我更傾向於將哪些項目納入庫或框架:
庫 | 框架 |
---|---|
Backbone | Ember |
Knockout | AngularJS |
Spine | Batman |
CanJS | Meteor |
使用這些項目構建真實世界的應用的時候還須要哪些庫?如下的圖表展現了爲了保證開發效率每一個庫所需的依賴,以及這些依賴的大小。
經過從cdnjs下載庫,咱們收集了這些數據。在實踐中,大多數的項目會使用jQuery配合這些框架處理DOM,由於須要動畫和AJAX。在移動應用中,使用Zepto.js來代替jQuery處理DOM不是什麼稀奇的事。Zepto.js是一個比jQuery輕量得多的庫。雖然Zepto.js不支持Internet Explorer,可是移動應用一般不須要爲此操心。AngularJS包含了一個jQuery 的縮減版jQLite。可是若是你在項目中使用了jQuery的話,它會被覆蓋。AngularJS團隊鼓勵開發者,如非必要,不要添加完整的jQuery庫。爲了幫助你作出正確的選擇,下面的表格同時顯示了移動版(假定使用Zepto.js)和web版(假定使用jQuery)。
這一部分討論是否框架設計爲控制整個頁面或者它能夠被用於現存頁面的一個部分——你可能想漸漸將新技術引入現有的項目。前面的庫和框架的討論基本能夠體現每一個項目的互操做性,庫更傾向於很容易地集成到現存的項目,而框架爲你作更多的事,可是不容易和其餘項目配合。
AngularJS能夠和其餘庫很好地配合,可是它鼓勵開發者們考慮是否能夠不用jQuery和jQueryUI.事實上Angular內置了一個jQuery的子集jqLite。遵循這一實踐的理由是讓單元測試更容易,由於不少依賴庫和插件設計的時候沒有考慮單元測試,相應地更難和單元測試配合。在實踐中,大多數的開發者最終仍是由於某些特性使用了jQuery.
因爲Backbone的小尺寸和無預設的架構,將其包含在衆多流行的客戶端庫和服務器端技術中很容易。
被設計爲在運行時控制整個頁面,因此不太適合用於頁面的部分。
能夠在項目中做爲小組件使用,不控制整個頁面。
記者採訪音樂家時最愛問的問題是「你在成長的時候聽哪些藝術家的音樂,或者說,誰啓發了你?」這個問題經常使得讀者可以預期音樂家的聲樂。這些框架中大部分的觀念都不是全新的,而是來自於創造者之前工做的項目中喜歡的部分。這一部分總結了我從框架創造者的訪談中收集到的關於啓發的信息。
HTML類的聲明性的語言,Adobe和Flex、微軟的WPF\Silverligt等RIA技術給AngularJS的影響很深。這些聲明性技術沒有」主體「方法,僅僅表達須要發生什麼,而不指定具體實現。視圖和模型中的數據雙向綁定是這一聲明式編程風格在絕佳例子。此外,在Google的服務器端Java代碼中大量使用的依賴注入和IOC容器(特別是Juice)也啓發了AngularJS的創造者。他們重視單元測試,須要框架被設計容許依賴注入,這樣測試就能夠從其餘應用層剝離出來,運行起來也會更快。
Tom Dale在Quora上談了Ember受到的影響:
Ember.js剛開始開發的時候,咱們從Cocoa等本地應用程序框架引入一些概念,不事後來咱們以爲這些概念弊大於利,或者說它們和Web應用程序格格不入。所以,咱們開始從Ruby on Rails和Backbone.js 等開源項目中尋找靈感。所以,Ember.js結合了本地應用的強大和現代web的輕量。
此外,Ember.js是SproutCore JavaScript庫的進化版,SproutCore中止仿效Cocoa而更多地借鑑jQuery的時候,Ember誕生了,理解這一點很重要。
hanselminutes的播客提供了Steve Sanderson受到哪些方面啓發的背景信息。總結一下,MVVM設計模式和微軟的WPF、Sliverlight等聲明性技術是最大的啓發者。你可能會發現Knockout的最佳特性——聲明性的數據雙向綁定——和Anjular類似,由於二者的啓發者是類似的。
報紙在報道新聞的時候努力保持中立。惟一的例外是編者案,鼓勵表達觀點,做者一般在問題上佔據一個強烈的立場。可是大多數狀況,這二者既不是嚴格的中立報道,也不是強烈的意見表達,而是位於二者之間的連續統。技術框架也有相似的劃分,便是否強主張。例如,Ruby on Rails推崇約定優於配置,而且爲開發者作了大量決定,包括文件結構和數據訪問。相應地,它被認爲是強主張的。其餘Sinatra類的服務器端框架更輕量,並不預設文件結構和數據訪問。相應的,被當作是無主張的。服務端框架有理念,客戶端JavaScript MVC框架一樣有,咱們討論的框架也能夠被置於強主張和無主張的連續統中考察。讓咱們看看每一個項目,而後討論他們的理念。
Backbone是最開明的框架,極度無主張,容許開發者作出本身的決定,有時這會致使代碼差別過大而難以維護。惟一的例外是Backbone假定服務器端有一個REST服務,我會在特性部分詳細討論這一點。這一假定能夠經過覆蓋模型的sync方法來繞過。
AngularJS有較強的主張,特別是它強調可測試性和依賴注入。此外,HTML類的聲明性編程很棒的理念也在框架中普遍體現。
Ember力求開發者僅對應用的特有部分做決定,其他所有交給約定和支架。這個理念和Ruby on Rails和jQuery很接近。這一理念最好的表達出如今emberjs.com的網站上:
不要浪費時間作那些可有可無的選擇。Ember.js吸納了常見的慣用法,所以你能夠專一於應用的特殊部分,而不是從新發明輪子。
Ember標準化了文件和url結構,固然,有必要的時候也容許你覆蓋這些設定。你能夠預期的是大量的代碼會爲你生成,大量的相似文件結構的約定。相應地,你須要作出的常規選擇更少,由於框架已經爲你選定了合理的默認值,你能夠着手構建你的應用的特殊部分。
路由和數據存儲留給開發者決定。不預設文件或URL結構。甚至容許用基於字符串的模板替換聲明性的基於DOM的模板。
咱們能夠將這些JavaScript MVC框架當作是幫助開發者構建單頁應用的經常使用特性集合。每一個框架實現這些特性的方式,或者不實現這些特性的方式(經過其餘庫來補全框架的功能)是值得留心的。
除此之外,一些框架提供經常使用的語言層面的服務,例如通用的pub/sub事件模型和麪向對象的繼承支持。
這是最受吹捧的特性。你經過HTML input修改了數據,綁定到input的JavaScript對象立刻更新,其餘綁定的用戶接口元素也隨之更新。在不少框架中,反之亦然。若是你修改了JavaScript對象,html會自動刷新。這是一個web上的雙向的數據綁定,咱們在Flex、Windows Forms、WPF等富客戶端應用框架中見過這類綁定。如下的表格顯示了哪些框架支持數據綁定。
有些人可能持有異議,由於Backbone和Spine部分支持數據綁定。可是我以爲大量工做須要留給開發者,保險起見,不如說這些庫不支持這些特性。
客戶端的JavaScript數據模型須要穿插在HTML中,這些框架採用兩種方式解決問題。
基於字符串的模板(目前最流行的是handlebars.js),將字符串、文本模板中的動態部分替換爲模型中的數據。字符串常被提到也飽受爭議的特性之一是性能。其缺點是調試控制語句類的邏輯很困難。
基於DOM的模板擁抱標記語言的聲明式本性,這是開了掛的html,經過html中的附加屬性來描述須要的綁定和事件。這些庫須要的代碼大大減小,爲開發者作了不少事情。
一些框架(Backbone、Spine)更專一於模型,要求開發者在base模型的基礎上擴展JavaScript類,經過.get()
和.set()
訪問屬性,這樣就能跟蹤改動,模型的變更也會觸發事件。KnockoutJS讓開發者在原始的JavaScript對象上應用可察封裝,而後經過object.propertyName()
訪問屬性(當心,別丟了括號)。
其餘庫(AngularJS)對頁面上的全部綁定的DOM元素做髒檢查,由於沒有標準的get和set訪問器。所以將這些庫用於大頁面時將致使性能問題。這些庫不只須要更少的刷新模板的代碼,也不須要你使用特定的get和set訪問器來修改模型中的數據,因此你可使用原始的JavaScript對象。這大大提高了開發效率,這一點在框架的初學者身上體現得尤其明顯。
這些框架經過如下方式將數據存儲到服務器
一些框架默認預設後端有很是整潔的REST JSON服務,而且,至少在默認的狀況下,前端與後端頻繁交互,在後臺異步更新數據,而用戶界面響應流暢。這些框架內部使用jQuery或Zepto發送合適的AJAX請求給服務器。用戶界面的HTML DOM元素監聽應用的JavaScript對象模型的改動,同步機制獲得模型屬性的更改提醒,將改動發送給REST服務,確保模型和服務器同步。
Backbone默認在客戶端保存數據以前發送請求,這樣服務器端和客戶端同步就很容易。和Backbone很是相似的Spine框架,採用了不一樣的方式,在異步發送請求到服務器前,先在客戶端存儲記錄,這提供了更好的用戶界面響應,在移動應用中常發生的離線狀態下也能工做。若是你的項目須要支持離線,須要瞭解清楚框架對該特性的支持
這些框架要求開發者使用$.ajax
(jQuery)來調用服務,或者添加兼容的開源庫處理數據存儲需求。
Meteor之類精心製做的框架擁有更完整的數據存儲方案,可是要求服務器端有MongoDB數據庫。這類方案試圖提供一個擴展性優異的默認解決方案,提供從頭至尾的JavaScript開發體驗。
如下的表格總結了每一個框架是如何處理數據存儲的。
將URL路由映射到JavaScript函數,能夠支持瀏覽器的後退按鈕。單頁應用最大的缺點之一是因爲頁面無刷新,瀏覽器歷史不會添加條目,因此後退按鈕一般沒法將用戶帶回頁面的前一狀態,除非開發者在主要的狀態改變時作一些額外的工做,經過在URL後附加井號,或者,使用現代瀏覽器的push和pop狀態,實現狀態跟蹤機制。總之,大多數項目都提供基本、初步而有用的功能。Knockout的作法很簡單,容許你使用其餘的第三方開源庫。
考察各個框架的特性以後,我發現我並非在作一個「蘋果對蘋果」的比較。一個更爲公平的比較也許是將AngularJS和EmberJS之類全面的框架與配合第三方庫使用的Backbone和KnockoutJS之類的MV*框架進行比較。具體來講,下面的比較會更有意義:
之後的博客中我會繼續深刻。
爲項目選擇JavaScript MVC框架時有大量須要考慮的事項,我但願本文是一個良好的開始。請在評論中分享你使用這些框架的體驗,包括它們的優異之處,也包括它們使用上的陷阱。
原文 Choosing a JavaScript MVC Framework
翻譯 SegmentFault