AngularJS 、Backbone.js 和 Ember.js 的比較

oschina發表於2014-08-26

 1 介紹

  我們準備在這篇文章中比較三款流行於Web的“模型-檢視-*”框架:AngularJS、Backbone和Ember。為你的專案選擇正確的框架能夠對你及時交付專案的能力和在以後維護你自己程式碼的能力產生巨大影響。你也許想基於一款可靠的、穩定的和成熟的框架來構建專案,但又不想為此受到約束。Web發展迅速——新技術產生,舊的那套方法很快跟不上潮流。如此形勢之下,我們準備仔細深入的比較這三個框架。

 2  框架概覽

  今天我們提到的所有框架有許多共同點:都是開源的,遵從 MIT 協議,並且都嘗試通過 MV* 模式來解決開發單頁面應用的問題。它們都有類似的概念:檢視,事件,資料模型和路由。我們先簡單回顧一下有關的歷史和背景知識,然後再展開深入比較這三款框架。

  AngularJS 誕生於 2009 年,當時作為一個大型商業產品的一部分叫做 GetAngular。不久之後,Misko Hevery,GetAngular 專案建立者之一,花了僅僅三週時間,用 GetAngular 重寫了一個曾經耗時 6 個月才完成的,有 17K 行程式碼的頁面應用,並將程式碼削減到 1,000 行左右,於是成功的說服了谷歌開始贊助該專案,並將其開源,也就是我們今天看到 AngularJS 。Angular 的特點是擁有雙向資料繫結,依賴注入,易於測試的編碼風格,以及通過使用自定義指令可以簡單的擴充套件 HTML。

  Backbone.js 是一個輕量級的 MVC 框架。誕生於 2010 年,它作為那種笨重全功能的 MVC 框架,比如說 ExtJS, 的一個代替品,迅速流行開來。 很多服務都使用了它,比如 Pinterest, Flixster, AirBNB 等等。

  Ember 則要回溯到 2007 年,最開始是以 SproutCore MVC 框架展現在世人面前,由 SproutIt 開發,後來是 Apple,再後來到 2011 的時候,jQuery 和 Ruby on Rails 的核心貢獻者 Yehuda Katz 參與了進來。有名的 Ember 使用者包括了 Yahoo!, Groupon, 和 ZenDesk。

 3 社群

  社群是在選擇一個框架的時候,要考慮的最重要因素之一。大社群意味著更多的答案,更多的第三方模組,更多的 YouTube 教程…你,明白了麼。我做了個統計,截止 2014年8月16日,Angular 是絕對的王者,作為 GitHub 上第六大星級專案,在 StackOverflow 上的提問比 Ember 和 Backbone 加起來還多,你自己看:

Github 的點贊星數 27.2k 18.8k 11k
第三方模組 800 ngmodules 236 backplugs 21 emberaddons
棧爆網的提問件數 49.5k 15.9k 11.2k
YouTube 件數 ~75k ~16k ~6k
GitHub 貢獻者 928 230 393
Chrome 外掛使用者 150k 7k 38.3k
指標 AngularJS Backbone.js Ember.js

  所有這些指標,顯示的僅僅是每個框架的當前狀態。看看哪個框架增長最快也是很有趣的,你有福了,通過穀人希的趨勢跟蹤,你可以得到以下答案:

  http://www.google.com/trends/explore?hl=en-US#q=ember.js,+angularjs,+backbone.js&cmpt=q

 4 框架大小

  頁面的載入時間是你網站成功的關鍵。當涉及瀏覽速度的時候,使用者沒太多耐性 — 所以很多情況下你要儘可能讓你的應用跑得越快越好。使用框架,有兩個因素會對應用的載入時間產生影響: 框架的大小和它啟動的時間。

  Javascript 資源通常都會被經過精簡和壓縮,所以我們來比較一下壓縮版。但是隻看框架的大小肯定不夠的。Backbone.js,儘管是最小的 (只有 6.5kb),但是必須 Underscore.js (5kb) 和 jQuery (32kb) 或者 Zepto (9.1kb),而且你還有可能還有一些第三方外掛要加進來。

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,把這個選擇權留給了你。感受模板引擎的異同最好的辦法就是上點程式碼,好的,我們開始。我們將演示把一個列表轉換成 HTML 列表的例子。

  5.1 AngularJS

  Angular 的模板引擎僅僅是在 HTML 上使用繫結表示式。而繫結表示式又僅僅是兩層大括號而已:

<ul>
  <li ng-repeat="framework in frameworks" 
      title="{{framework.description}}">
    {{framework.name}}
  </li>
</ul>

  5.2 Backbone.js

  Backbone 可以和許多第三方模板引擎整合,預設的選擇是 Underscore 模板。 因為 Underscore 是 Backbone 的依賴項,你已經把它載入到頁面中了,你無須新增任何額外的依賴關係就可以使用它的模板引擎。不爽的是,Underscore 的模板引擎非常初級,你通常不得不把 javascript 混進去,比如說:

<ul>
  <% _.each(frameworks, function(framework) { %>
    <li title="<%- framework.description %>">
      <%- framework.name %>
    </li>
  <% }); %>
</ul>

  5.3 Ember.js

  Ember 目前用的是 Handlebars 模板引擎,熱門的 Mustache 模板引擎的擴充套件。一個新的 Handlebars 變種,叫做 HTMLBars ,目前已經可以使用了。Handlebars 不關心 DOM – 它所做的僅僅是做一個簡單的字串變換。而 HTMLBars 則可以處理 DOM,所有的變數轉換都有上下文感知。由於 HTMLBars 還沒有流行,我們還是來看看用 Handlebars 方式列印列表方式:

<ul>
  {{#each frameworks}}
    <li {{bind-attr title=description}}>
      {{name}}
    </li>
  {{/each}}
</ul>

 6 AngularJS

  6.1 好處

  Angular 為 Web 開發帶來了許多創新的概念。雙向資料繫結節省了大量的樣板程式碼。比如下面的 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 中扮演了一個重要的角色。Javascript 是單執行緒,基於事件迴圈的語言,這意味著許多操作(比如說網路通訊)都是以非同步方式進行的。非同步的 Javascript 程式碼會很快的就陷入了長長的巢狀回撥,也就是臭名昭著的 “Pyramid Code” 或者叫做 “Callback Hell”。

  相對比另外兩個,Angular 不光有著更大的社群,更多的線上文件,而且還有谷歌在背後的推廣和支援。所以,核心團隊還在不斷增長,產出更多的創新,以及改善開發生產效率的工具,比如: Protractor, Batarang, ngmin 和 Zone.js,一抓一大把。而且,開發團隊還向使用者徵集需求。比如說,Angular 2.0 的所有設計文件你都可以從 這裡 找到,任何人都可以直接給設計文件提建議。

  Angular 幫助你把構建應用的程式塊劃分為下面這幾種型別:控制器(Controller),指令(Directive),工廠(Factory),過濾器(Filter),服務(Service)和檢視(View) (就是模板)。它們被組織為模組形式,之後可以被另一個引用。每種型別有不同的作用。檢視處理 UI,控制器處理 UI 背後的邏輯,服務用來處理和後臺的通訊,並且將共通的有關聯的功能元件結合在一起,而指令通過定義新的元素,屬性和行為,很容易的構造可重用的元件,以及HTML擴充套件。

  自動髒值檢查意味著,你不需要用 getter 和 setter 去訪問資料模型 — 你可以修改任意範圍(scope)的任意屬性,然後 angular 會自動檢測到變化,通知該屬性的所有觀察者(watcher)。

  “Angular 的初衷是寫出可測試的程式碼。” 單元測試指南中的這句話,包含了太多意思 – Angular 確實很注重分離,單元隔離,為 $http 和 $timeout 等基礎內建服務提供了現成的,強大的 mock。

  6.2 痛處

  Angular 常被人詬病的是指令那複雜的 API。 Transclusion,尤為突出,這個概念,把許多開發者搞得一頭霧水,讓你滿腦子各種概念,比如編譯函式(compiling function),linking,函式的預處理/後處理(pre/post linking functions),各種 scope 型別 (transclusion/isolate/child scope),還有各種配置設定,需要相當的時間來掌握。

  Angular 中的 scope 層次結構使用的是 Prototypal 繼承,這又是一個為了迎合從面嚮物件語言,比如 Java 和 C#,過來的開發人員而提出的概念。不理解 scope 導致許多開發者開發很受傷 (比如說: , 還有)。

  Angular 表示式 在檢視層被廣泛應用。表示式語言非常強大,有時候是強大過頭了。這誘導開發者使用各種複雜的邏輯,甚至執行賦值運算和計算全部都放在模板中。把邏輯運算放在模板中讓它非常難以測試,因為它變成不可能獨立測試了。看看下面的例子,演示瞭如何濫用這種模板語言的:

<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>

  許多情況下,指令名稱的拼寫錯誤,或者呼叫未定義 scope 方法,都會被忽略,並且很難被發現,特別是當你把複雜的指令 API 和上面提到的 scope 的繼承弄到一起的時候。我見過有些苦逼花費一大堆時間抓耳撓腮想找出為什麼 scope 中的一個繫結的事件沒被回撥函式觸發,最後居然是因為用了駝峰(camelCase)命名,而沒有用連字元分隔(hyphen-separated)拼寫屬性的名稱(比如說).

  最後,是 Angular 的迴圈系統中, 要注意那“神奇的”髒值檢查,它經常會給開發者驚喜。在非-Angular上下文執行的時候,很容易忘記呼叫 $digest() (例子)。也就是說,你必須非常小心,不要觸發緩慢的觀察者事件或者無限迴圈(例子: , 還有 )。通常,對於一頁上有大量的互動元素的頁面,Angular會變得非常慢。有個很好的界定是,不要在同一頁面上放超過 2,000 個活動的繫結。

 7 Backbone.js

  7.1 好處

  Backbone 輕量,快速,記憶體佔用小。學習曲線也是很平緩的,只需要幾個簡單的概念就能掌握 (模型/集合, 檢視, 路由)。它有很棒的文件,程式碼簡單,註釋詳細,並且這裡還有一個註釋版原始碼,用來解釋框架的工作細節。實際上你可以通讀整個框架的原始碼,用不到一個小時去熟悉它。

  因為又小又基礎,你可以基於 Backbone 打造你自己的框架。一些基於 Backbone 的第三方框架的例子有 Aura, Backbone UI, Chaplin, Geppetto, Marionette, LayoutManager, Thorax, Vertebrae。用 Angular 和 Ember 你一般都要用框架作者給你的選擇,有些可能會不適合你的工程需求和個人風格。Angular 2.0 承諾改變這種情況,通過構建更小的獨立模組,使你可以選擇和組合它們。不過我們還沒看到它什麼時候才能交付。

  7.2 痛處

  Backbone 沒有提供基本構造。它僅僅是提供了一些基礎工具讓你去建立,讓你去決定如何構造應用,這有太多空要填了。比如說記憶體管理需要小心的處理。由於缺失檢視生命週期管理,這會使得路由/狀態的變化,很容易導致記憶體洩漏,除非你可以很清楚的處理一切。

  誠然,Backbone本身不提供的功能,可以由第三方外掛來填補,這也就意味著,在你建立應用的時候,有很多選擇,因為一個功能通常有許多個備選外掛。比如說,內嵌模型可以由下面這些外掛提供:Backbone.DocumentModel, BackBone.NestedTypes, Backbone.Schema, Backbone-Nested, backbone-nestify, 這還是其中的一小部分。決定哪個更適合你的工程是需要調查的,這需要時間 — 而使用框架的一個主要目的是節省你的時間。

  Backbone 缺乏對雙向資料繫結的支援,意思也就是說,你必須編寫大量的樣板來處理模型更新之後觸發的檢視更新。看看上面給出的例子,想想看 Angular.js 的雙向資料繫結削減了多少樣板程式碼。

  Backbone 中的檢視是直接操作 DOM 的,這讓它們非常難做單元測試,也就更脆弱,更難以重用。常見的例子就是用 CSS 選擇器查詢 DOM 元素,改變CSS 類名,新增有同樣類名的新元素或者把同樣的 DOM 樹包裝到另一個元素,都會打亂你的 CSS 選擇器以及應用的渲染。

 8 Ember.js

  8.1 好處

  Ember.js 主張約定優於配置。也就是說,無需編寫大量的樣板程式碼,Ember 會自動推匯出許多配置本身,比如在定義一個路由資源的時候,可以自動判定路由的名稱和控制器。Ember 甚至會在你沒定義控制器的時候,自動為你的資源生成一個。

  Ember 包含了一個優秀的路由和一個可選的資料層,叫做 ember data。和其他兩個框架不同,它們的資料層非常小(Backbone 的集合/模型和 Angular 的 $resource),Ember 有一個拿來即用的非常成熟的資料模組,只需要簡單的配置,就可以和後臺的 Ruby-on-Rails 或者其它的 RESTful JSON API 整合得非常好。它還可以通過設定 fixtures來支援面向 mock API 開發以及測試。

  效能是 Ember.js 設計的主要目標。諸如 The Run Loop 這個概念,可以確保資料的變化只導致單個 DOM 更新,即使同一塊資料進行了多次更新也是一樣,還有計算屬性的快取, 還有可以在編譯時或在服務端對 HandleBars 模板進行預編譯的能力,都可以幫助你保證應用的負載,保證它跑得足夠快。

  8.2 痛處

  Ember 的 API 在它穩定版出來之前變化太大了。這導致了有大量的過期內容和不能再執行的例子,這會新進開發者開始使用這個框架時感到非常困惑。看看 Ember Data 變更日誌,你就會知道我說的是什麼意思了。這裡有太多的大變更了,這就讓許多棧爆網的回答和編碼例子變得毫無意義了(比如說這)

  Handlebars 為了保持模板和資料模型一致,用了太多的 <script> 標籤來汙染 DOM 了。這會在遷移到 HTMLBars 的時候變得毫無意義,但到那時,你的 DOM 樹上全都是 <script> 標籤,會幾乎無法辨認哪些是你的程式碼了。還有最糟糕的部分 – 這會打亂你的CSS樣式,或者影響和其他框架的整合,比如說 jQuery UI 的排序

 9 總結

  我們已經看過三個框架的長處短處。Ember 的綜合能力,其中的 MVC 結構,對於那些曾經在 Ruby, Python, Java, C# 或者其他面嚮物件語言中有過 MVC 程式設計背景知識的程式設計師來說非常有意義。Ember 還帶來了媲美桌面應用的效能,而且還因為約定優於配置的原因,可以讓你節省非常多樣板程式碼。

  Backbone 崇尚極簡主義。它夠小,夠快,夠簡單,但是提供了你構建應用所需要的最小集(許多情況下,甚至要小於最小集)。

  Angular 的擴充套件 HTML 的創新方法,對於骨子裡是 web 開發者的人來說非常有意義。它有強大的社群,有谷歌在後面支援它,它不斷沉澱和成長。它不但適用於快速原型開發,還適用於大型生產應用。

  原文地址:http://www.airpair.com/js/javascript-framework-comparison

相關文章