Discourse的推出在整個社區賺足了眼球。Discourse選擇Ember.JS做爲前端MVC框架,其開發者Robin Ward寫了博客分享選擇Ember.js的理由javascript
最近Quora網站上也有人提問,Angular.js和 Ember.js,哪一個JavaScript框架更好?php
這個問題獲得了熱烈的迴應,兩個框架的開發者都參與了。html
Misko Hevery(Angular.js的開發者之一)回答了這一問題,他的主要觀點以下:前端
在HTML中加入太多邏輯不是好作法。Angular.js只放置綁定,而不是邏輯,建議把邏輯放入控制器中。但綁定一樣是信息,一般,這些信息能夠放在三個地方:java
Angular.js的獨特之處在於它擁抱HTML/CSS,其餘一些框架提供了它們本身的API,偏離了HTML。Angular.js在全部框架中是能體現聲明式編程範式的。聲明式編程很是適合用來編寫用戶界面,編寫邏輯則交給JavaScript。node
Angular.js容許你擴展HTML,因此你在使用Angular.js過程當中遇到的任何問題均可以很容易地克服。git
Tom Dale(Ember.js的開發者之一)仔細比較了Angular.js和Ember.js.angularjs
Dale首先來介紹了Ember.js項目的由來。從2009年開始,我就一直在蘋果公司參與 SproutCore 項目的開發,SproutCore 是一個 相似Cocoa的JavaScript開源框架,後來演變成了iCloud。當時,我身邊是一些世界上最好的Cocoa開發者。github
問題在於,客戶端應用程序這麼多年來彷佛並無真正新的突破。自80年代以來就一直遵循的基本模型——代碼運行在本地計算機上,從網絡上獲取數據,而後在本地處理,並顯示在屏幕上;而現在惟一改變的是——代碼運行在瀏覽器的沙箱環境中,而後加載所需的「二進制」文件,而不是由用戶安裝到硬盤上的文件。編程
在考慮這些問題時,我首先去想,在咱們以前,人們已經作了什麼?我認爲框架的做用無需爭辯。好比Cocoa,不管在Mac仍是iOS上,Cocoa均可以讓開發者輕鬆編寫受用戶喜好的應用程序。
咱們但願開發者可以建立雄心勃勃的、可以與本地應用競爭的Web應用。要達成這一目標,開發者須要先進的工具和正確的理念。
Ember.js剛開始開發的時候,咱們從Cocoa等本地應用程序框架引入一些概念,不事後來咱們以爲這些概念弊大於利,或者說它們和Web應用程序格格不入。所以,咱們開始從Ruby on Rails和Backbone.js 等開源項目中尋找靈感。
在Dale看來,與Ember.js相比,Angular.js更像一個研究項目。好比,在學習文檔中,Ember.js主要討論模型、視圖和控制器,而Angular.js指南要求你去學習一些相似於範圍、指示符和transclusion方面的內容等。
一些大公司已經在Ember.js上投入了大量時間和精力,好比ZenDesk對Backbone.js失望後使用Ember.js重寫,Square的整個Web層面也是基於Ember.js的,Groupon的移動版Web應用也是使用Ember.js開發的。此外,還有不少創業公司經過Ember.js得到了成功,並開始回饋Ember.js社區。
而目前所看到使用Angular.js開發的大多數應用程序只是演示項目,或是Google的內部項目。
Yehuda(Ember.js開發者之一)和我也一直積極邀請真正的用戶參與Ember.js框架的設計和維護,這能夠確保咱們在Ember.js中添加的功能對於實際開發是有用的。
事實上,在過去的幾個月中,大多數Ember.js開發工做都是由Ember.js社區的核心貢獻組完成的,他們來自不一樣的公司。若是Yehuda和我哪天有什麼事情,或者咱們的公司倒閉了,Ember.js還將會持續發展。這是一個真正的社區項目,而不是「Google」項目。
Angular.js使用有語義意義的屬性(好比data-ng-repeat)來實現模板。
而Ember.js使用Handlebars來描述HTML。
Handlebars語法(相似{{\#each}}
),和Angular.js那樣使用額外的屬性作法,哪一種更美觀,是一個見仁見智的問題。我我的認爲,HTML屬性有點雜亂,可讀性要差些。固然,若是Ember.js不存在,而我又必須使用一個使用了數據屬性的框架,那麼我會考慮Angular.js。
拋開美觀不談,我相信,Ember.js使用基於字符串的模板有以下優點:
此外,Handlebars只讓你綁定屬性,而Angular.js容許你嵌入實時更新的任意表達式。剛開始不少人認爲這是Ember.js的侷限性,但實際上:
Angular.js一般依靠一種叫作「dirty checking」的機制來肯定對象是否已進行更改。在你掃描每一個對象和其全部綁定屬性時,比較當前值和以前已知的值。若是它發生了變化,就須要更新綁定。但Angular.js開發者很是聰明,使用「髒檢查」,你不須要使用accessors。你能夠用person.name = "Bill"
來代替person.set('name', "Bill")
,就像在Ember.js 或 Backbone.js中的同樣。然而,使用「髒檢查」,你沒法一次有超過2000個綁定對象。
我認爲這很好地說明了Ember.js 和 Angular.js理念上的區別。Ember.js 和 Angular.js都力求簡單和易用。而Ember.js使你沒必要擔憂代碼中是否有超過2000個綁定。若是你正在編寫大型應用程序,那麼你已經解決了你所擔憂的最大的事情。對於中小規模的應用程序來講,Angular.js一樣是偉大的,由於這些應用程序不會觸及Angular.js的限制區。
在Ember.js中,咱們老是但願利用瀏覽器和語言中的新功能,以便使事情變得更容易。例如,一旦ES6中 代理對象(proxies)可用,咱們不會再要求你使用get()
和set()
。
因此這就是爲何我認爲——若是你想構建雄心勃勃的應用程序,你應該選擇Ember.js。
此外,在開發過程當中,咱們對於性能方面和如何利用語言新特性方面也考慮了好久。Yehuda Katz和我一塊兒開發Ember.js,他同時也是TC39(負責JavaScript下一個版本的制定)的成員,在此方面至關有經驗。
angularjs_scaffold的開發者Patrick Aljord也參與了討論。
angularjs_scaffold是基於Angular.js編寫的針對scaffolding視圖的Rails插件。
Patrick Aljord闡述了選擇Angula.js的理由。
事實上,我本來打算在項目中使用Ember.js,由於我比較信賴Yehuda(Ember.js開發者之一),他在Rails和jQuery方面的工做很傑出。可是Ember.js中隨時會變化的API和匱乏的文檔,使我一再推遲使用它。偶然發現了Angular.js以後,我被它吸引了。
正如Tom Dale(Ember.js開發者之一)所說,Ember.js受到了Cocoa 和Rails啓發。問題在於,在Ember.js下工做,我並無真正感受到像在寫一個Web應用程序。而Angular.js讓我感受像在寫一個Web應用程序,它真正支持全部的Web概念,並以一種很是天然的方式來擴展HTML。
事實上,Angular.js並無使用本身的對象或重寫JS方法,當你使用Angular.js時,你就使用了純JS,而且Angular.js實現的許多概念都將直接進入下一個版本的Javascript中。
學習Angular.js,就意味着學習將來的Javascript,而學習Ember.js,你只是學習到了Ember的特有概念。
來看個例子。HTML是偉大的,由於它是聲明式的,若是想要定義一個段落,你只需寫以下代碼:
<p>Hello world</p>
可是若是你想很是動態地實現?你須要經過相似於下面的代碼來引導瀏覽器:
<p id="greeting1"></p> <script> var isIE = document.attachEvent; var addListener = isIE ? function(e, t, fn) { e.attachEvent('on' + t, fn);} : function(e, t, fn) { e.addEventListener(t, fn, false);}; addListener(document, 'load', function(){ var greeting = document.getElementById('greeting1'); if (isIE) { greeting.innerText = 'Hello World!'; } else { greeting.textContent = 'Hello World!'; } }); </script>
來看看Angular.js如何實現:
<p>{{hello}}</p>
再來看一個示例,若是你要遍歷一個數組,只需:
<ul> <li ng-repeat="element in array">element</li> </ul>
這個語法看起來像新的 MDV標準。這看起來比Ember.js更加簡潔。另外,Angular.js被優化得很是快,開發團隊經過以下措施來實現:
一些顯示Angular.js的速度要快於Ember.js,例如 Angular VS Knockout VS Ember。
Angular.js將來會擁有可複用的組件,這容許你編寫很是簡潔的代碼。這是Web的將來。
此外,Angular.js還擁有一個龐大的社區和 大量的貢獻者。
Discoures開發者Evil Trout在本身的博客上對比了這兩個框架。Evil Trout列舉了AngularJS的一些缺陷:
如今我知道如今爲何AngularJS勢頭愈來愈大:由於它很簡單。一個精簡了許多高級概念與實現的框架,會所以變得更容易學習。若是要我給這些框架排個名次的話,Angularjs大概是介於Backbone和Ember之間。
若是您的應用程序是簡單,那麼使用簡單的框架想來也是極好。但若是你是要構建大規模的應用程序的話就要謹慎選擇了,並且要進行長期的維護。
比起AngularJS,Ember有更多須要學習的概念。當你因爲Ember的複雜性放棄它的時候,請考慮爲何開發人員添加了這些所謂多餘的東西。事物的存在總有它的道理。
你會發現Ember是一個充滿概念與實用的工具集,若是你想創建一個龐大的、可維護的應用程序。它的API側重於經過一個健全的方式幫助你結構代碼。Ember有一些AngularJS框架沒有的理念。
AngularJS吹捧本身爲MVC框架,或者是MVW(Model View Whatever)框架。
很明顯的,AngularJS的View層是:讓你經過ng-*
屬性和handlebars風格的{{variable}}
表達式來標註HTML文檔。Controller層是JavaScript類經過ng-controller
屬性的元素綁定DOM元素。
特別是,若是你有一個Server端的MVC背景, AngularJS的Model層該是什麼樣的,這點並不明確。並且在AngularJS中,並無標準來定義了一個模型應該是Model基類,仍是一個component(組件)或interface(接口)。
在一個AngularJS的Controller層中,有一個$scope
對象。全部附加的數據經過它綁定在你的HTML模板:
function SomeCtrl($scope) { $scope.countries = ['can', 'usa', 'fra', 'jap']; $scope.user = {name: "Evil Trout"}; $scope.age = 34; // 咱們的模板如今能夠渲染 {{age}}, {{user.name}} 和不少國家了! }
根據AngularJS的文檔,在AngularJS中全部聲明在$scope上
的對象都是一個Model,不只僅對象和數組是Model,連primitive也是!
在模板中,AngularJS提供給你所需的工具來管理單一數據來源。這是一個叫數據綁定的概念。若是咱們建立了一個模板中有一個AngularJS表達式{{age}}
,咱們說這綁定於$scope.age
這個Model。若是你在一個模板中多處書寫{{age}}
,並在Controller層中執行 $scope.age = 40
,全部綁定的值都會同時更新。
然而,若是你真正想表達單一數據來源,你所須要的是在二級的數據綁定,就在你的數據Model自己。換句話說,AngularJS的短板在於:只容許將數據綁定在$scope和模板之間,而不是在Javascript代碼的結構中。
在Ember中,全部Model擴展在 Ember.Object
基類上。所以你可以在Model內部聲明對象之間的關係。例如:
App.Room = Ember.Object.extend({ area: function() { return this.get('width') * this.get('height'); }.property('width', 'height') });
在這裏,咱們已經建立了一個名爲Room
的Model。咱們已經聲明area
爲計算屬性。property
通知Ember,Room
的area
屬性取決於其width
和height
屬性。
建立一個Room Model的實例仍是很容易的:
var room = App.Room.create({width: 10, height: 5});
如今咱們能夠建立一個模板:
<p>Room:</p> <p>{{width}} ft.</p> <p>{{height}} ft.</p> <p>{{area}} sq ft.</p>
相應的Ember會正確地渲染這些屬性。在這種狀況下,area不得不與 width和 height同步更新。若是這兩個屬性的變化,area將自動更新。
由於在AngularJS中,Model都是普通的Javascript對象,AngularJS沒有計算屬性。可是,您能夠在相應的對象上經過函數模擬來實現:
var Room = function(args) { this.width = args.width; this.height = args.height; } Room.prototype.area = function() { return this.width * this.height; }
要訪問咱們的房間的面積,你必須添加一組括號area()調用:
<p>Room:</p> <p>{{width}} ft.</p> <p>{{height}} ft.</p> <p>{{area()}} sq ft.</p>
這顯示了Ember和AngularJS之間的關鍵區別。Ember遵循統一訪問原則 。 在一個Ember模板中,不管你所訪問的是計算屬性仍是primitive,表達方式看上去是同樣的。而在AngularJS中,必須明確區分函數。
這可能會致使可維護性的惡夢。在一個大型軟件項目中,隨着時間的推移,你將不可避免地要迭代原有的代碼。在Ember中,你能夠垂手可得地作到這點;而在AngularJS你就不得不更新每個綁定於這個Model的模板。
這個相關的權衡是值得討論的,你可能已經注意到,在Ember中,爲了訪問一個Model的屬性,你必須使用getter
和setter
。這意味着須要一點點額外的代碼,但你收穫的是和模板中JavaScrip同樣的好處:用函數替換primitive能夠工做!
使用getter
和setter
的另外一個好處是能夠保證安全。思考下面的代碼:
console.log(room.inhabitant.name);
若是inhabitant
不存在,會發生什麼事? 你會獲得一個JavaScript錯誤。而在Ember中,你會獲得undefined
返回值,這使得你更容易編寫健壯的代碼。
// 輸出 undefined console.log(room.get('inhabitant.name'));
AngularJS相比Ember來講更難複用對象實例。例如在Ember模板中,能夠經過{{linkTo}}
helper連接到另外一個路由:
<ul> {{#each user in users}} <li>{{linkTo 'users.show' user}}Show {{username}}{{/linkTo}}</li> {{/each}} </ul>
這裏,咱們遍歷一個用戶列表,並建立一個連接。當你的鼠標懸停在連接上,若是你的路由配置正確,你會看到一些/users/show/123
之類的文字。 然而,你點擊連接時,Ember實際上經過你所配置的其餘路由到達相關的用戶頁面。
Ember的路由器足夠聰明,若是這個用戶的id已經在內存中,Ember不會重複解析。而在AngularJS中,每次訪問路由,它傳遞一個id並在Controller層進行解析。
一個長存的瀏覽器應用程序的巨大優點之一是能夠重用的對象,就像上面那個用戶導航的例子。AngularJS並無遵循這一理念,它鼓勵你扔掉它,而後再次找到它(多是從Server端再次獲取數據!)。
你是否曾經也糾結於Angular.js和Ember.js的選擇,歡迎分享你的經驗和心得。