1 介紹
我們準(zhǔn)備在這篇文章中比較三款流行于Web的“模型-視圖-*”框架:AngularJS、Backbone和Ember。為你的項(xiàng)目選擇正確的框架能夠?qū)δ慵皶r(shí)交付項(xiàng)目的能力和在以后維護(hù)你自己代碼的能力產(chǎn)生巨大影響。你也許想基于一款可靠的、穩(wěn)定的和成熟的框架來構(gòu)建項(xiàng)目,但又不想為此受到約束。Web發(fā)展迅速——新技術(shù)產(chǎn)生,舊的那套方法很快跟不上潮流。如此形勢(shì)之下,我們準(zhǔn)備仔細(xì)深入的比較這三個(gè)框架。
2 框架概覽
今天我們提到的所有框架有許多共同點(diǎn):都是開源的,遵從 MIT 協(xié)議,并且都嘗試通過 MV* 模式來解決開發(fā)單頁面應(yīng)用的問題。它們都有類似的概念:視圖,事件,數(shù)據(jù)模型和路由。我們先簡(jiǎn)單回顧一下有關(guān)的歷史和背景知識(shí),然后再展開深入比較這三款框架。
AngularJS 誕生于 2009 年,當(dāng)時(shí)作為一個(gè)大型商業(yè)產(chǎn)品的一部分叫做 GetAngular。不久之后,Misko Hevery,GetAngular 項(xiàng)目創(chuàng)建者之一,花了僅僅三周時(shí)間,用 GetAngular 重寫了一個(gè)曾經(jīng)耗時(shí) 6 個(gè)月才完成的,有 17K 行代碼的頁面應(yīng)用,并將代碼削減到 1,000 行左右,于是成功的說服了谷歌開始贊助該項(xiàng)目,并將其開源,也就是我們今天看到 AngularJS 。Angular 的特點(diǎn)是擁有雙向數(shù)據(jù)綁定,依賴注入,易于測(cè)試的編碼風(fēng)格,以及通過使用自定義指令可以簡(jiǎn)單的擴(kuò)展 HTML。
Backbone.js 是一個(gè)輕量級(jí)的 MVC 框架。誕生于 2010 年,它作為那種笨重全功能的 MVC 框架,比如說 ExtJS, 的一個(gè)代替品,迅速流行開來。 很多服務(wù)都使用了它,比如 Pinterest, Flixster, AirBNB 等等。
Ember 則要回溯到 2007 年,最開始是以 SproutCore MVC 框架展現(xiàn)在世人面前,由 SproutIt 開發(fā),后來是 Apple,再后來到 2011 的時(shí)候,jQuery 和 Ruby on Rails 的核心貢獻(xiàn)者 Yehuda Katz 參與了進(jìn)來。有名的 Ember 用戶包括了 Yahoo!, Groupon, 和 ZenDesk。
3 社區(qū)
社區(qū)是在選擇一個(gè)框架的時(shí)候,要考慮的最重要因素之一。大社區(qū)意味著更多的答案,更多的第三方模塊,更多的 YouTube 教程…你,明白了么。我做了個(gè)統(tǒng)計(jì),截止 2014年8月16日,Angular 是絕對(duì)的王者,作為 GitHub 上第六大星級(jí)項(xiàng)目,在 StackOverflow 上的提問比 Ember 和 Backbone 加起來還多,你自己看:
| Github 的點(diǎn)贊星數(shù) | 27.2k | 18.8k | 11k |
| 第三方模塊 | 800 ngmodules | 236 backplugs | 21 emberaddons |
| 棧爆網(wǎng)的提問件數(shù) | 49.5k | 15.9k | 11.2k |
| YouTube 件數(shù) | ~75k | ~16k | ~6k |
| GitHub 貢獻(xiàn)者 | 928 | 230 | 393 |
| Chrome 插件用戶 | 150k | 7k | 38.3k |
| 指標(biāo) | AngularJS | Backbone.js | Ember.js |
|---|
所有這些指標(biāo),顯示的僅僅是每個(gè)框架的當(dāng)前狀態(tài)??纯茨膫€(gè)框架增長(zhǎng)最快也是很有趣的,你有福了,通過谷人希的趨勢(shì)跟蹤,你可以得到以下答案:
http://www.google.com/trends/explore?hl=en-US#q=ember.js,+angularjs,+backbone.js&cmpt=q
4 框架大小
頁面的加載時(shí)間是你網(wǎng)站成功的關(guān)鍵。當(dāng)涉及瀏覽速度的時(shí)候,用戶沒太多耐性 — 所以很多情況下你要盡可能讓你的應(yīng)用跑得越快越好。使用框架,有兩個(gè)因素會(huì)對(duì)應(yīng)用的加載時(shí)間產(chǎn)生影響: 框架的大小和它啟動(dòng)的時(shí)間。
Javascript 資源通常都會(huì)被經(jīng)過精簡(jiǎn)和壓縮,所以我們來比較一下壓縮版。但是只看框架的大小肯定不夠的。Backbone.js,盡管是最小的 (只有 6.5kb),但是必須 Underscore.js (5kb) 和 jQuery (32kb) 或者 Zepto (9.1kb),而且你還有可能還有一些第三方插件要加進(jìn)來。
| AngularJS 1.2.22 | 39.5kb | 39.5kb |
| Backbone.js 1.1.2 | 6.5kb |
43.5kb (jQuery + Underscore) 20.6kb (Zepto + Underscore) |
| Ember.js 1.6.1 | 90kb | 136.2kb (jQuery + Handlebars) |
| 框架 | 凈大小 | 包含依賴之后的大小 |
|---|
5 模板
Angular 和 Ember 都有模板引擎。而另一方面 Backbone,把這個(gè)選擇權(quán)留給了你。感受模板引擎的異同最好的辦法就是上點(diǎn)代碼,好的,我們開始。我們將演示把一個(gè)列表轉(zhuǎn)換成 HTML 列表的例子。
5.1 AngularJS
Angular 的模板引擎僅僅是在 HTML 上使用綁定表達(dá)式。而綁定表達(dá)式又僅僅是兩層大括號(hào)而已:
<ul>
<li ng-repeat="framework in frameworks"
title="{{framework.description}}">
{{framework.name}}
</li>
</ul>
5.2 Backbone.js
Backbone 可以和許多第三方模板引擎集成,默認(rèn)的選擇是 Underscore 模板。 因?yàn)?Underscore 是 Backbone 的依賴項(xiàng),你已經(jīng)把它加載到頁面中了,你無須添加任何額外的依賴關(guān)系就可以使用它的模板引擎。不爽的是,Underscore 的模板引擎非常初級(jí),你通常不得不把 javascript 混進(jìn)去,比如說:
<ul>
<% _.each(frameworks, function(framework) { %>
<li title="<%- framework.description %>">
<%- framework.name %>
</li>
<% }); %>
</ul>
5.3 Ember.js
Ember 目前用的是 Handlebars 模板引擎,熱門的 Mustache 模板引擎的擴(kuò)展。一個(gè)新的 Handlebars 變種,叫做 HTMLBars ,目前已經(jīng)可以使用了。Handlebars 不關(guān)心 DOM – 它所做的僅僅是做一個(gè)簡(jiǎn)單的字符串變換。而 HTMLBars 則可以處理 DOM,所有的變量轉(zhuǎn)換都有上下文感知。由于 HTMLBars 還沒有流行,我們還是來看看用 Handlebars 方式打印列表方式:
<ul>
{{#each frameworks}}
<li {{bind-attr title=description}}>
{{name}}
</li>
{{/each}}
</ul>
6 AngularJS
6.1 好處
Angular 為 Web 開發(fā)帶來了許多創(chuàng)新的概念。雙向數(shù)據(jù)綁定節(jié)省了大量的樣板代碼。比如下面的 jQuery 代碼片段:
$('#greet-form input.user-name').on('value', function() {
$('#greet-form div.user-name').text('Hello ' + this.val() + '!');
});
由于 Angular 的雙向綁定,你根本就不需要自己寫代碼。只需要在 HTML 模板里面聲明綁定就可以了:
<input ng-model="user.name" type="text" />
Hello {{user.name}}!
Promises 在 Angular 中扮演了一個(gè)重要的角色。Javascript 是單線程,基于事件循環(huán)的語言,這意味著許多操作(比如說網(wǎng)絡(luò)通訊)都是以異步方式進(jìn)行的。異步的 Javascript 代碼會(huì)很快的就陷入了長(zhǎng)長(zhǎng)的嵌套回調(diào),也就是臭名昭著的 “Pyramid Code” 或者叫做 “Callback Hell”。
相對(duì)比另外兩個(gè),Angular 不光有著更大的社區(qū),更多的在線文檔,而且還有谷歌在背后的推廣和支持。所以,核心團(tuán)隊(duì)還在不斷增長(zhǎng),產(chǎn)出更多的創(chuàng)新,以及改善開發(fā)生產(chǎn)效率的工具,比如: Protractor, Batarang, ngmin 和 Zone.js,一抓一大把。而且,開發(fā)團(tuán)隊(duì)還向用戶征集需求。比如說,Angular 2.0 的所有設(shè)計(jì)文檔你都可以從 這里 找到,任何人都可以直接給設(shè)計(jì)文檔提建議。
Angular 幫助你把構(gòu)建應(yīng)用的程序塊劃分為下面這幾種類型:控制器(Controller),指令(Directive),工廠(Factory),過濾器(Filter),服務(wù)(Service)和視圖(View) (就是模板)。它們被組織為模塊形式,之后可以被另一個(gè)引用。每種類型有不同的作用。視圖處理 UI,控制器處理 UI 背后的邏輯,服務(wù)用來處理和后臺(tái)的通信,并且將共通的有關(guān)聯(lián)的功能組件結(jié)合在一起,而指令通過定義新的元素,屬性和行為,很容易的構(gòu)造可重用的組件,以及HTML擴(kuò)展。
自動(dòng)臟值檢查意味著,你不需要用 getter 和 setter 去訪問數(shù)據(jù)模型 — 你可以修改任意范圍(scope)的任意屬性,然后 angular 會(huì)自動(dòng)檢測(cè)到變化,通知該屬性的所有觀察者(watcher)。
“Angular 的初衷是寫出可測(cè)試的代碼?!?單元測(cè)試指南中的這句話,包含了太多意思 – Angular 確實(shí)很注重分離,單元隔離,為 $http 和 $timeout 等基礎(chǔ)內(nèi)置服務(wù)提供了現(xiàn)成的,強(qiáng)大的 mock。
6.2 痛處
Angular 常被人詬病的是指令那復(fù)雜的 API。 Transclusion,尤為突出,這個(gè)概念,把許多開發(fā)者搞得一頭霧水,讓你滿腦子各種概念,比如編譯函數(shù)(compiling function),linking,函數(shù)的預(yù)處理/后處理(pre/post linking functions),各種 scope 類型 (transclusion/isolate/child scope),還有各種配置設(shè)置,需要相當(dāng)?shù)臅r(shí)間來掌握。
Angular 中的 scope 層次結(jié)構(gòu)使用的是 Prototypal 繼承,這又是一個(gè)為了迎合從面向?qū)ο笳Z言,比如 Java 和 C#,過來的開發(fā)人員而提出的概念。不理解 scope 導(dǎo)致許多開發(fā)者開發(fā)很受傷 (比如說: 這, 這 還有這)。
Angular 表達(dá)式 在視圖層被廣泛應(yīng)用。表達(dá)式語言非常強(qiáng)大,有時(shí)候是強(qiáng)大過頭了。這誘導(dǎo)開發(fā)者使用各種復(fù)雜的邏輯,甚至執(zhí)行賦值運(yùn)算和計(jì)算全部都放在模板中。把邏輯運(yùn)算放在模板中讓它非常難以測(cè)試,因?yàn)樗兂刹豢赡塥?dú)立測(cè)試了??纯聪旅娴睦樱菔玖巳绾螢E用這種模板語言的:
<button ng-click="(oldPassword && checkComplexity(newPassword) && oldPassword != newPassword) ? (changePassword(oldPassword, newPassword) && (oldPassword=(newPassword=''))) : (errorMessage='Please input a new password matching the following requirements: ' + passwordRequirements)">Click me</button>
許多情況下,指令名稱的拼寫錯(cuò)誤,或者調(diào)用未定義 scope 方法,都會(huì)被忽略,并且很難被發(fā)現(xiàn),特別是當(dāng)你把復(fù)雜的指令 API 和上面提到的 scope 的繼承弄到一起的時(shí)候。我見過有些苦逼花費(fèi)一大堆時(shí)間抓耳撓腮想找出為什么 scope 中的一個(gè)綁定的事件沒被回調(diào)函數(shù)觸發(fā),最后居然是因?yàn)橛昧笋劮?camelCase)命名,而沒有用連字符分隔(hyphen-separated)拼寫屬性的名稱(比如說這).
最后,是 Angular 的循環(huán)系統(tǒng)中, 要注意那“神奇的”臟值檢查,它經(jīng)常會(huì)給開發(fā)者驚喜。在非-Angular上下文運(yùn)行的時(shí)候,很容易忘記調(diào)用 $digest() (例子)。也就是說,你必須非常小心,不要觸發(fā)緩慢的觀察者事件或者無限循環(huán)(例子: 這, 這 還有 這)。通常,對(duì)于一頁上有大量的交互元素的頁面,Angular會(huì)變得非常慢。有個(gè)很好的界定是,不要在同一頁面上放超過 2,000 個(gè)活動(dòng)的綁定。
7 Backbone.js
7.1 好處
Backbone 輕量,快速,內(nèi)存占用小。學(xué)習(xí)曲線也是很平緩的,只需要幾個(gè)簡(jiǎn)單的概念就能掌握 (模型/集合, 視圖, 路由)。它有很棒的文檔,代碼簡(jiǎn)單,注釋詳細(xì),并且這里還有一個(gè)注釋版源碼,用來解釋框架的工作細(xì)節(jié)。實(shí)際上你可以通讀整個(gè)框架的源碼,用不到一個(gè)小時(shí)去熟悉它。
因?yàn)橛中∮只A(chǔ),你可以基于 Backbone 打造你自己的框架。一些基于 Backbone 的第三方框架的例子有 Aura, Backbone UI, Chaplin, Geppetto, Marionette, LayoutManager, Thorax, Vertebrae。用 Angular 和 Ember 你一般都要用框架作者給你的選擇,有些可能會(huì)不適合你的工程需求和個(gè)人風(fēng)格。Angular 2.0 承諾改變這種情況,通過構(gòu)建更小的獨(dú)立模塊,使你可以選擇和組合它們。不過我們還沒看到它什么時(shí)候才能交付。
7.2 痛處
Backbone 沒有提供基本構(gòu)造。它僅僅是提供了一些基礎(chǔ)工具讓你去創(chuàng)建,讓你去決定如何構(gòu)造應(yīng)用,這有太多空要填了。比如說內(nèi)存管理需要小心的處理。由于缺失視圖生命周期管理,這會(huì)使得路由/狀態(tài)的變化,很容易導(dǎo)致內(nèi)存泄漏,除非你可以很清楚的處理一切。
誠然,Backbone本身不提供的功能,可以由第三方插件來填補(bǔ),這也就意味著,在你創(chuàng)建應(yīng)用的時(shí)候,有很多選擇,因?yàn)橐粋€(gè)功能通常有許多個(gè)備選插件。比如說,內(nèi)嵌模型可以由下面這些插件提供:Backbone.DocumentModel, BackBone.NestedTypes, Backbone.Schema, Backbone-Nested, backbone-nestify, 這還是其中的一小部分。決定哪個(gè)更適合你的工程是需要調(diào)查的,這需要時(shí)間 — 而使用框架的一個(gè)主要目的是節(jié)省你的時(shí)間。
Backbone 缺乏對(duì)雙向數(shù)據(jù)綁定的支持,意思也就是說,你必須編寫大量的樣板來處理模型更新之后觸發(fā)的視圖更新。看看上面給出的例子,想想看 Angular.js 的雙向數(shù)據(jù)綁定削減了多少樣板代碼。
Backbone 中的視圖是直接操作 DOM 的,這讓它們非常難做單元測(cè)試,也就更脆弱,更難以重用。常見的例子就是用 CSS 選擇器查找 DOM 元素,改變CSS 類名,添加有同樣類名的新元素或者把同樣的 DOM 樹包裝到另一個(gè)元素,都會(huì)打亂你的 CSS 選擇器以及應(yīng)用的渲染。
8 Ember.js
8.1 好處
Ember.js 主張約定優(yōu)于配置。也就是說,無需編寫大量的樣板代碼,Ember 會(huì)自動(dòng)推導(dǎo)出許多配置本身,比如在定義一個(gè)路由資源的時(shí)候,可以自動(dòng)判定路由的名稱和控制器。Ember 甚至?xí)谀銢]定義控制器的時(shí)候,自動(dòng)為你的資源生成一個(gè)。
Ember 包含了一個(gè)優(yōu)秀的路由和一個(gè)可選的數(shù)據(jù)層,叫做 ember data。和其他兩個(gè)框架不同,它們的數(shù)據(jù)層非常小(Backbone 的集合/模型和 Angular 的 $resource),Ember 有一個(gè)拿來即用的非常成熟的數(shù)據(jù)模塊,只需要簡(jiǎn)單的配置,就可以和后臺(tái)的 Ruby-on-Rails 或者其它的 RESTful JSON API 集成得非常好。它還可以通過設(shè)置 fixtures來支持面向 mock API 開發(fā)以及測(cè)試。
性能是 Ember.js 設(shè)計(jì)的主要目標(biāo)。諸如 The Run Loop 這個(gè)概念,可以確保數(shù)據(jù)的變化只導(dǎo)致單個(gè) DOM 更新,即使同一塊數(shù)據(jù)進(jìn)行了多次更新也是一樣,還有計(jì)算屬性的緩存, 還有可以在編譯時(shí)或在服務(wù)端對(duì) HandleBars 模板進(jìn)行預(yù)編譯的能力,都可以幫助你保證應(yīng)用的負(fù)載,保證它跑得足夠快。
8.2 痛處
Ember 的 API 在它穩(wěn)定版出來之前變化太大了。這導(dǎo)致了有大量的過期內(nèi)容和不能再運(yùn)行的例子,這會(huì)新進(jìn)開發(fā)者開始使用這個(gè)框架時(shí)感到非常困惑??纯?nbsp;Ember Data 變更日志,你就會(huì)知道我說的是什么意思了。這里有太多的大變更了,這就讓許多棧爆網(wǎng)的回答和編碼例子變得毫無意義了(比如說這)。
Handlebars 為了保持模板和數(shù)據(jù)模型一致,用了太多的 <script> 標(biāo)簽來污染 DOM 了。這會(huì)在遷移到 HTMLBars 的時(shí)候變得毫無意義,但到那時(shí),你的 DOM 樹上全都是 <script> 標(biāo)簽,會(huì)幾乎無法辨認(rèn)哪些是你的代碼了。還有最糟糕的部分 – 這會(huì)打亂你的CSS樣式,或者影響和其他框架的集成,比如說 jQuery UI 的排序。
9 總結(jié)
我們已經(jīng)看過三個(gè)框架的長(zhǎng)處短處。Ember 的綜合能力,其中的 MVC 結(jié)構(gòu),對(duì)于那些曾經(jīng)在 Ruby, Python, Java, C# 或者其他面向?qū)ο笳Z言中有過 MVC 編程背景知識(shí)的程序員來說非常有意義。Ember 還帶來了媲美桌面應(yīng)用的性能,而且還因?yàn)榧s定優(yōu)于配置的原因,可以讓你節(jié)省非常多樣板代碼。
Backbone 崇尚極簡(jiǎn)主義。它夠小,夠快,夠簡(jiǎn)單,但是提供了你構(gòu)建應(yīng)用所需要的最小集(許多情況下,甚至要小于最小集)。
Angular 的擴(kuò)展 HTML 的創(chuàng)新方法,對(duì)于骨子里是 web 開發(fā)者的人來說非常有意義。它有強(qiáng)大的社區(qū),有谷歌在后面支持它,它不斷沉淀和成長(zhǎng)。它不但適用于快速原型開發(fā),還適用于大型生產(chǎn)應(yīng)用。
原文地址:http://www.airpair.com/js/javascript-framework-comparison
哈爾濱品用軟件有限公司致力于為哈爾濱的中小企業(yè)制作大氣、美觀的優(yōu)秀網(wǎng)站,并且能夠搭建符合百度排名規(guī)范的網(wǎng)站基底,使您的網(wǎng)站無需額外費(fèi)用,即可穩(wěn)步提升排名至首頁。歡迎體驗(yàn)最佳的哈爾濱網(wǎng)站建設(shè)。
