Vue.js vs React vs Angular 深度對比

天府雲創發表於2016-12-29

這個頁面無疑是最難編寫的,但我們認為它也是非常重要的。或許你曾遇到了一些問題並且已經用其他的框架解決了。你來這裡的目的是看看 Vue 是否有更好的解決方案。這也是我們在此想要回答的。

客觀來說,作為核心團隊成員,顯然我們會更偏愛 Vue,認為對於某些問題來講用 Vue 解決會更好。如果沒有這點信念,我們也就不會整天為此忙活了。但是在此,我們想盡可能地公平和準確地來描述一切。其他的框架也有顯著的優點,例如 React 龐大的生態系統,或者像是 Knockout 對瀏覽器的支援覆蓋到了 IE6。我們會嘗試著把這些內容全部列出來。

我們也希望得到的幫助,來使文件保持最新狀態,因為 JavaScript 的世界進步的太快。如果你注意到一個不準確或似乎不太正確的地方,請提交問題讓我們知道。

React

React 和 Vue 有許多相似之處,它們都有:

  • 使用 Virtual DOM
  • 提供了響應式(Reactive)和元件化(Composable)的檢視元件。
  • 將注意力集中保持在核心庫,伴隨於此,有配套的路由和負責處理全域性狀態管理的庫。

由於有著眾多的相似處,我們會用更多的時間在這一塊進行比較。這裡我們不只保證技術內容的準確性,同時也兼顧了平衡的考量。我們需要指出 React 比 Vue 更好的地方,像是他們的生態系統和豐富的自定義渲染器。

React社群為我們準確進行平衡的考量提供了非常積極地幫助,特別感謝來自 React 團隊的 Dan Abramov 。他非常慷慨的花費時間來貢獻專業知識,幫助我們完善這篇文件,最後我們對最終結果都十分滿意

效能簡介

到目前為止,針對現實情況的測試中,Vue 的效能是優於 React 的。如果你對此表示懷疑,請繼續閱讀。我們會解釋為什麼會這樣(並且會提供一個與 React 團隊共同約定的比較基準)。

渲染效能

在渲染使用者介面的時候,DOM 的操作成本是最高的,不幸的是沒有庫可以讓這些原始操作變得更快。
我們能做到的最好效果就是:

  1. Minimize the number of necessary DOM mutations. Both React and Vue use virtual DOM abstractions to accomplish this and both implementations work about equally well.
  2. Add as little overhead (pure JavaScript computations) as possible on top of those DOM manipulations. This is an area where Vue and React differ.

The JavaScript overhead is directly related to the mechanisms of computing the necessary DOM operations. Both Vue and React utilizes Virtual DOM to achieve that, but Vue’s Virtual DOM implementation (a fork of snabbdom) is much lighter-weight and thus introduces less overhead than React’s.

Vue 和 React 也提供功能性元件,這些元件因為都是沒有宣告,沒有例項化的,因此會花費更少的開銷。當這些都用於關鍵效能的場景時,Vue 將會更快。為了證明這點,我們建立了一個簡單的參照專案,它負責渲染 10,000 個列表項 100 次。我們鼓勵你基於此去嘗試執行一下。然而在實際上,由於瀏覽器和硬體的差異甚至 JavaScript 引擎的不同,結果都會相應有所不同。

如果你懶得去做,下面的數值是來自於一個 2014 年產的 MacBook Air 並在 Chrome 52 版本下執行所產生的。為了避免偶然性,每個參照專案都分別執行 20 次並取自最好的結果:

  Vue React
Fastest 23ms 63ms
Median 42ms 81ms
Average 51ms 94ms
95th Perc. 73ms 164ms
Slowest 343ms 453ms

更新效能

In React, when a component’s state changes, it triggers the re-render of the entire component sub-tree, starting at that component as root.

To avoid unnecessary re-renders of child components, you need to implementshouldComponentUpdate everywhere and use immutable data structures. In Vue, a component’s dependencies are automatically tracked during its render, so the system knows precisely which components actually need to re-render.

這意味著,未經優化的 Vue 相比未經優化的 React 要快的多。由於 Vue 改進過渲染效能,甚至全面優化過的 React 通常也會慢於開箱即用的 Vue。

開發中

顯然,在生產環境中的效能是至關重要的,目前為止我們所具體討論的便是針對此環境。但開發過程中的表現也不容小視。不錯的是用 Vue 和 React 開發大多數應用的速度都是足夠快的。

然而,假如你要開發一個對效能要求比較高的資料視覺化或者動畫的應用時,你需要了解到下面這點:在開發中,Vue 每秒最高處理 10 幀,而 React 每秒最高處理不到 1 幀。

Both Vue and React remain fast enough in development for most normal applications. However, when prototyping high frame-rate data visualizations or animations, we’ve seen cases of Vue handling 10 frames per second in development while React dropping to about 1 frame per second.

這是由於 React 有大量的檢查機制,這會讓它提供許多有用的警告和錯誤提示資訊。我們同樣認為這些是很重要的,但是我們在實現這些檢查時,也更加密切地關注了效能方面。

HTML & CSS

在 React 中,它們都是 JavaScript 編寫的,聽起來這十分簡單和優雅。然而不幸的事實是,JavaScript 內的 HTML 和 CSS 會產生很多痛點。在 Vue 中我們採用 Web 技術並在其上進行擴充套件。接下來將通過一些例項向你展示這意味的是什麼。

JSX vs Templates

在 React 中,所有的元件的渲染功能都依靠 JSX。JSX 是使用 XML 語法編寫 Javascript 的一種語法糖。這有一個通過React社群稽核過的例子

render () {
let { items } = this.props
let children
if ( items.length > 0 ) {
children = (
<ul>
{items.map( item =>
<li key={item.id}>{item.name}</li>
)}
</ul>
)
else {
children = <p>No items found.</p>
}
return (
<div className = ‘list-container’>
{children}
</div>
)
}

JSX 的渲染功能有下面這些優勢:

  • 你可以使用完整的程式語言 JavaScript 功能來構建你的檢視頁面。
  • 工具對 JSX 的支援相比於現有可用的其他 Vue 模板還是比較先進的(比如,linting、型別檢查、編輯器的自動完成)。

在 Vue 中,由於有時需要用這些功能,我們也提供了渲染功能 並且支援了 JSX。然而,對於大多陣列件來說,渲染功能是不推薦使用了。

在這方面,我們提供的是更簡單的模板:

<template>
<div class=“list-container”>
<ul v-if=“items.length”>
<li v-for=“item in items”>
{{ item.name }}
</li>
</ul>
<p v-else>No items found.</p>
</div>
</template>

優點如下:

  • 在寫模板的過程中,樣式風格已定並涉及更少的功能實現。
  • 模板總是會被宣告的。
  • 模板中任何 HTML 語法都是有效的。
  • 閱讀起來更貼合英語(比如,for each item in items)。
  • 不需要高階版本的 JavaScript 語法,來增加可讀性。

這樣,不僅開發人員更容易編寫程式碼,設計人員和開發人員也可以更容易的分析程式碼和貢獻程式碼。

這還沒有結束。Vue 擁抱 HTML,而不是用 JavaScript 去重塑它。在模板內,Vue 也允許你用前處理器比如 Pug(原名 Jade)。

div.list-container
ul(v-if=”items.length”)
li(v-for=”item in items”) {{ item.name }}
p(v-else) No items found.

CSS 的元件作用域

除非你把元件分佈在多個檔案上(例如 CSS Modules),要不在 React 中作用域內的 CSS 就會產生警告。非常簡單的 CSS 還可以工作,但是稍微複雜點的,比如懸停狀態、媒體查詢、偽類選擇符等要麼通過沉重的依賴來重做要麼就直接不能用。

而 Vue 可以讓你在每個單檔案元件中完全訪問 CSS。

<style scoped>
@media (min-width: 250px) {
.list-container:hover {
background: orange;
}
}
</style>

這個可選 scoped 屬性會自動新增一個唯一的屬性(比如 data-v-21e5b78)為元件內 CSS 指定作用域,編譯的時候 .list-container:hover 會被編譯成類似.list-container[data-v-21e5b78]:hover

最後,就像 HTML 一樣,你可以選擇自己偏愛的 CSS 前處理器編寫 CSS。這可以讓你圍繞設計為中心展開工作,而不是引入專門的庫來增加你應用的體積和複雜度。

規模

向上擴充套件

Vue 和 React 都提供了強大的路由來應對大型應用。React 社群在狀態管理方面非常有創新精神(比如Flux、Redux),而這些狀態管理模式甚至 Redux 本身也可以非常容易的整合在 Vue 應用中。實際上,Vue 更進一步地採用了這種模式(Vuex),更加深入整合 Vue 的狀態管理解決方案 Vuex 相信能為你帶來更好的開發體驗。

兩者另一個重要差異是,Vue 的路由庫和狀態管理庫都是由官方維護支援且與核心庫同步更新的。React 則是選擇把這些問題交給社群維護,因此建立了一個更分散的生態系統。但相對的,React 的生態系統相比 Vue 更加繁榮。

最後,Vue 提供了Vue-cli 腳手架,能讓你非常容易地構建專案,包含了 Webpack,Browserify, 甚至 no build system。React 在這方面也提供了create-react-app,但是現在還存在一些侷限性:

  • 它不允許在專案生成時進行任何配置,而 Vue 支援 Yeoman-like 定製。
  • 它只提供一個構建單頁面應用的單一模板,而 Vue 提供了各種用途的模板。
  • 它不能用使用者自建的模板構建專案,而自建模板對企業環境下預先建立協議是特別有用的。

而要注意的是這些限制是故意設計的,這有它的優勢。例如,如果你的專案需求非常簡單,你就不需要自定義生成過程。你能把它作為一個依賴來更新。如果閱讀更多關於不同的設計理念

向下擴充套件

React 學習曲線陡峭,在你開始學 React 前,你需要知道 JSX 和 ES2015,因為許多示例用的是這些語法。你需要學習構建系統,雖然你在技術上可以用 Babel 來實時編譯程式碼,但是這並不推薦用於生產環境。

就像 Vue 向上擴充套件好比 React 一樣,Vue 向下擴充套件後就類似於 jQuery。你只要把如下標籤放到頁面就可以執行:

<script src="https://unpkg.com/vue/dist/vue.js"></script>

然後你就可以編寫 Vue 程式碼並應用到生產中,你只要用 min 版 Vue 檔案替換掉就不用擔心其他的效能問題。

由於起步階段不需學 JSX,ES2015 以及構建系統,所以開發者只需不到一天的時間閱讀指南就可以建立簡單的應用程式。

本地渲染

ReactNative 能使你用相同的元件模型編寫有本地渲染能力的 APP(IOS 和 Android)。能同時跨多平臺開發,對開發者是非常棒的。相應地,Vue 和 Weex 會進行官方合作,Weex 是阿里的跨平臺使用者介面開發框架,Weex 的 JavaScript 框架執行時用的就是 Vue。這意味著在 Weex 的幫助下,你使用 Vue 語法開發的元件不僅僅可以執行在瀏覽器端,還能被用於開發 IOS 和 Android 上的原生應用。

在現在,Weex 還在積極發展,成熟度也不能和 ReactNative 相抗衡。但是,Weex 的發展是由世界上最大的電子商務企業的需求在驅動,Vue 團隊也會和 Weex 團隊積極合作確保為開發者帶來良好的開發體驗。

MobX

Mobx 在 React 社群很流行,實際上在 Vue 也採用了幾乎相同的反應系統。在有限程度上,React + Mobx 也可以被認為是更繁瑣的 Vue,所以如果你習慣組合使用它們,那麼選擇 Vue 會更合理。

Angular 1

Vue 的一些語法和 Angular 的很相似(例如 v-if vs ng-if)。因為 Angular 是 Vue 早期開發的靈感來源。然而,Augular 中存在的許多問題,在 Vue 中已經得到解決。

複雜性

在 API 與設計兩方面上 Vue.js 都比 Angular 1 簡單得多,因此你可以快速地掌握它的全部特性並投入開發。

靈活性和模組化

Vue.js 是一個更加靈活開放的解決方案。它允許你以希望的方式組織應用程式,而不是在任何時候都必須遵循 Angular 1 制定的規則,這讓 Vue 能適用於各種專案。我們知道把決定權交給你是非常必要的。
這也就是為什麼我們提供 Webpack template,讓你可以用幾分鐘,去選擇是否啟用高階特性,比如熱模組載入、linting、CSS 提取等等。

資料繫結

Angular 1 使用雙向繫結,Vue 在不同元件間強制使用單向資料流。這使應用中的資料流更加清晰易懂。

指令與元件

在 Vue 中指令和元件分得更清晰。指令只封裝 DOM 操作,而元件代表一個自給自足的獨立單元 —— 有自己的檢視和資料邏輯。在 Angular 中兩者有不少相混的地方。

效能

Vue 有更好的效能,並且非常非常容易優化,因為它不使用髒檢查。

在 Angular 1 中,當 watcher 越來越多時會變得越來越慢,因為作用域內的每一次變化,所有 watcher 都要重新計算。並且,如果一些 watcher 觸發另一個更新,髒檢查迴圈(digest cycle)可能要執行多次。Angular 使用者常常要使用深奧的技術,以解決髒檢查迴圈的問題。有時沒有簡單的辦法來優化有大量 watcher 的作用域。

Vue 則根本沒有這個問題,因為它使用基於依賴追蹤的觀察系統並且非同步佇列更新,所有的資料變化都是獨立觸發,除非它們之間有明確的依賴關係。

有意思的是,Angular 2 和 Vue 用相似的設計解決了一些 Angular 1 中存在的問題。

Angular 2

我們單獨將 Augluar 2 作分類,因為它完全是一個全新的框架。例如:它具有優秀的元件系統,並且許多實現已經完全重寫,API 也完全改變了。

TypeScript

Angular 1 面向的是較小的應用程式,Angular 2 已轉移焦點,面向的是大型企業應用。在這一點上 TypeScript 經常會被引用,它對那些喜歡用 Java 或者 C# 等型別安全的語言的人是非常有用的。

Vue 也十分適合製作企業應用,你也可以通過使用官方型別使用者貢獻的裝飾器來支援 TypeScript,這完全是自由可選的。

大小和效能

在效能方面,這兩個框架都非常的快。但目前尚沒有足夠的資料用例來具體展示。如果你一定要量化這些資料,你可以檢視第三方參照,它表明 Vue 2 相比 Angular2 是更快的。

在大小方面,雖然 Angular 2 使用 tree-shaking 和離線編譯技術使程式碼體積減小了許多。但包含編譯器和全部功能的 Vue2(23kb) 相比 Angular 2(50kb) 還是要小的多。但是要注意,用 Angular 2 的 App 的體積縮減是使用了 tree-shaking 移除了那些框架中沒有用到的功能,但隨著功能引入的不斷增多,尺寸會變得越來越大。

靈活性

Vue 相比於 Angular 2 則更加靈活,Vue 官方提供了構建工具來協助你構建專案,但它並不限制你去如何構建。有人可能喜歡用統一的方式來構建,也有很多開發者喜歡這種靈活自由的方式。

學習曲線

開始使用 Vue,你使用的是熟悉的 HTML、符合 ES5 規則的 JavaScript(也就是純 JavaScript)。有了這些基本的技能,你可以快速地掌握它(指南)並投入開發 。

Angular 2 的學習曲線是非常陡峭的。即使不包括 TypeScript,它的開始指南中所用的就有 ES2015 標準的 JavaScript,18個 NPM 依賴包,4 個檔案和超過 3 千多字的介紹,這一切都是為了完成個 Hello World。而Vue’s Hello World就非常簡單。甚至我們並不用花費一整個頁面去介紹它。

Ember

Ember 是一個全能框架。它提供了大量的約定,一旦你熟悉了它們,開發會變得很高效。不過,這也意味著學習曲線較高,而且並不靈活。這意味著在框架和庫(加上一系列鬆散耦合的工具)之間做權衡選擇。後者會更自由,但是也要求你做更多架構上的決定。

也就是說,我們最好比較的是 Vue 核心和 Ember 的模板資料模型層:

  • Vue 在普通 JavaScript 物件上建立響應,提供自動化的計算屬性。在 Ember 中需要將所有東西放在 Ember 物件內,並且手工為計算屬性宣告依賴。
  • Vue 的模板語法可以用全功能的 JavaScript 表示式,而 Handlebars 的語法和幫助函式相比來說非常受限。
  • 在效能上,Vue 甩開 Ember 幾條街,即使是 Ember 2.0 的最新 Glimmer 引擎。Vue 能夠自動批量更新,而 Ember 在關鍵效能場景時需要手動管理。

Knockout

Knockout 是 MVVM 領域內的先驅,並且追蹤依賴。它的響應系統和 Vue 也很相似。它在瀏覽器支援以及其他方面的表現也是讓人印象深刻的。它最低能支援到 IE6,而 Vue 最低只能支援到 IE9。

隨著時間的推移,Knockout 的發展已有所放緩,並且略顯有點老舊了。比如,它的元件系統缺少完備的生命週期事件方法,儘管這些在現在是非常常見的。以及相比於 Vue 呼叫子元件的介面它的方法顯得有點笨重。

如果你有興趣研究,你還會發現二者在介面設計的理念上是不同的。這可以通過各自建立的simple Todo List 體現出來。或許有點主觀,但是很多人認為 Vue 的 API 介面更簡單結構更優雅。

Polymer

Polymer 是另一個由谷歌贊助的專案,事實上也是 Vue 的一個靈感來源。Vue 的元件可以粗略的類比於 Polymer 的自定義元素,並且兩者具有相似的開發風格。最大的不同之處在於,Polymer 是基於最新版的 Web Components 標準之上,並且需要重量級的 polyfills 來幫助工作(效能下降),瀏覽器本身並不支援這些功能。相比而言,Vue 在支援到 IE9 的情況下並不需要依賴 polyfills 來工作,。

在 Polymer 1.0 版本中,為了彌補效能,團隊非常有限的使用資料繫結系統。例如,在 Polymer 中唯一支援的表示式只有布林值否定和單一的方法呼叫,它的 computed 方法的實現也並不是很靈活。

Polymer 自定義的元素是用 HTML 檔案來建立的,這會限制使用 JavaScript/CSS(和被現代瀏覽器普遍支援的語言特性)。相比之下,Vue 的單檔案元件允許你非常容易的使用 ES2015 和你想用的 CSS 預編譯處理器。

在部署生產環境時,Polymer 建議使用 HTML Imports 載入所有資源。而這要求伺服器和客戶端都支援 Http 2.0 協議,並且瀏覽器實現了此標準。這是否可行就取決於你的目標使用者和部署環境了。如果狀況不佳,你必須用 Vulcanizer 工具來打包 Polymer 元素。而在這方面,Vue 可以結合非同步元件的特性和 Webpack 的程式碼分割特性來實現懶載入(lazy-loaded)。這同時確保了對舊瀏覽器的相容且又能更快載入。

而 Vue 和 Web Component 標準進行深層次的整合也是完全可行的,比如使用 Custom Elements、Shadow DOM 的樣式封裝。然而在我們做出嚴肅的實現承諾之前,我們目前仍在等待相關標準成熟,進而再廣泛應用於主流的瀏覽器中。

Riot

Riot 2.0 提供了一個類似於基於元件的開發模型(在 Riot 中稱之為 Tag),它提供了小巧精美的 API。Riot 和 Vue 在設計理念上可能有許多相似處。儘管相比 Riot ,Vue 要顯得重一點,Vue 還是有很多顯著優勢的:

  • 根據真實條件來渲染,Riot 根據是否有分支簡單顯示或隱藏所有內容。
  • 功能更加強大的路由機制,Riot 的路由功能的 API 是極少的。
  • 更多成熟工具的支援。Vue 提供官方支援WebpackBrowserifySystemJS,而 Riot 是依靠社群來建立整合系統。
  • 過渡效果系統。Riot 現在還沒有提供。
  • 更好的效能。Riot 儘管聲稱其使用了虛擬 DOM,但實際上用的還是髒檢查機制,因此和 Angular 1 患有相同的效能問題。

相關文章