[vue3] vue3對比vue2優(yōu)化項簡要概述
不足與展望
Vue2的不足
- 源碼自身的可維護性較差;
- 數(shù)據(jù)量大后帶來渲染和更新的性能問題;
- 存在一些為了兼容但是和雞肋的API。
對Vue3的期望
- 更好的編程體驗;
- 更好的
TypeScript支持; - 更好的邏輯復用實踐。
從源碼、性能、語法API三大方面優(yōu)化框架。
Vue3的優(yōu)化
源碼優(yōu)化
源碼優(yōu)化的目的是讓代碼更易于開發(fā)和維護。
主要體現(xiàn)在使用monorepo管理源碼倉庫,以及使用TypeScript進行開發(fā)。
monorepo
monorepo將模塊拆分到不同的package中,每個package擁有各自的API、類型定義和測試。
這樣使得模塊拆分更細化,職責劃分更明確,模塊之間的依賴關系也更加明確。
開發(fā)人員也更容易閱讀、理解和更改所有模塊源碼,提高了代碼的可維護性。

使用mororepo還有一個好處是:package可以獨立于Vue.js使用,例如reactivity響應式庫。
如果用戶僅需要使用Vue.js 3.0的響應式功能,可以單獨依賴這個package而不需要依賴整個Vue.js,減小了引用包的體積大小。
TypeScript
使用TypeScript的好處是:
- 可以在編碼階段做類型檢查;
- 定義接口類型,有利于
IDE對變量類型的推導,開發(fā)更輕松。
Vue曾經(jīng)用過flow作為類型工具,但后來轉TypeScript了,原因在于:
TypeScript的社區(qū)更活躍;TypeScript在IDE中的支持更好;TypeScript有明確的版本發(fā)布策略,使得維護和升級更加可控,Flow的團隊后期爛尾。
一篇相關的文章:Flow vs Typescript: From Flow to Typescript. Why? - DEV Community
性能優(yōu)化
減小包體積
- 移除一些冷門的
feature,比如inline-template; - 引入
tree-shaking技術。
tree-shaking
tree-shaking依賴ES2015的模塊語法,通過編譯階段的靜態(tài)分析,找到?jīng)]有引入的模塊并打上標記。
在項目中沒有引入的模塊或組件,它們對應的代碼就不會被打包,也就間接減小了項目引入Vue.js包體積的目的。
數(shù)據(jù)劫持優(yōu)化
Vue最獨特的特性之一,是其非侵入性的響應式系統(tǒng)。
實現(xiàn)非侵入式的響應式系統(tǒng)的關鍵在于攔截對數(shù)據(jù)的讀寫操作。
響應式數(shù)據(jù)需要配置getter和setter。當渲染函數(shù)執(zhí)行時,讀取了數(shù)據(jù),觸發(fā)getter,在getter中將object[key]到依賴的映射記錄到Watcher中。
依賴是一個函數(shù),對于在
template中使用的響應式數(shù)據(jù)來說,它的依賴就是渲染函數(shù)。
當響應式數(shù)據(jù)被更新時,即被賦值,會觸發(fā)setter,在setter中根據(jù)object和key去Watcher中找到相對應的依賴函數(shù),執(zhí)行。即觸發(fā)了視圖更新。
總結:
- 在
getter中使用track函數(shù)收集依賴; - 在
setter中使用trigger函數(shù)觸發(fā)更新。
Vue2的做法
在Vue2中使用Object.defineProperty這個方法攔截對對象指定屬性的讀寫操作。
Object.defineProperty為對象的指定屬性設置getter和setter。
對于一個嵌套層級較深的對象來說,為了遍歷對象的每個屬性,需要遞歸調(diào)用,為每個屬性都設置getter&setter。
缺點:
-
遞歸調(diào)用會導致性能較差;
-
無法檢測
property的添加或移除,后來新增的屬性無法實現(xiàn)響應式;需要使用全局的
Vue.set方法或者組件內(nèi)部局部的this.$set方法,讓Vue有能力將依賴添加到Watcher中進行管理。 -
使用索引設置數(shù)組的某一項的值,無法被監(jiān)測到;
-
修改數(shù)組的
length屬性,不會觸發(fā)更新; -
無法應對
Map、Set這些集合類型的響應式,需要開發(fā)者自己想辦法解決。
這些缺點都來自于Object.defineProperty這個API本身的局限性。
Vue3的做法
在Vue3中,數(shù)據(jù)攔截使用了ES6的Proxy API,這個API可以直接將目標對象作為整體,攔截對它的各種操作,包括:
- 對某個屬性的讀/寫;
- 新增屬性;
- 刪除屬性;
Proxy可以Map/Set在getter攔截到對get/set/add等方法的調(diào)用。
因此,Vue3相比于Vue2:
- 解決了遞歸配置
getter&setter的問題; - 解決了新增/刪除屬性沒有響應式的問題;
- 實現(xiàn)了響應式的
Map/Set。
可以說Vue3在響應式這一部分的提升來自于ES6提供了更現(xiàn)代化更高效的API。
編譯優(yōu)化
在Vue2中,從new Vue()到生成DOM的過程大致如下:
上述的響應式過程發(fā)生在init階段,而template編譯為render function的階段可以在打包過程中完成。
而在運行時中,耗時較多的是patch階段。
Vue3在編譯階段優(yōu)化了編譯的結果,實現(xiàn)了對patch過程的優(yōu)化。
具體來說是通過flag標記、靜態(tài)提升的手段來實現(xiàn)的。
在Vue2中,數(shù)據(jù)更新并觸發(fā)重新渲染的粒度是組件級的。
在組件內(nèi)部仍然需要遍歷整顆VNode樹,如果組件包含許多靜態(tài)內(nèi)容,那么diff算法會在靜態(tài)內(nèi)容上浪費許多時間。
也就是說diff算法的效率由組件的虛擬DOM樹規(guī)模決定,而不是由動態(tài)節(jié)點的規(guī)模決定。
Vue3使用了Block Tree來優(yōu)化diff過程。
Block Tree
Block Tree 是一個將模板基于動態(tài)節(jié)點指令切割的嵌套區(qū)塊,每個區(qū)塊內(nèi)部的節(jié)點結構是固定的(
STABLE_FLAGMENT)。對于結構固定的區(qū)塊,僅需要使用一個
Array來追蹤其包含的動態(tài)節(jié)點。
借助 Block Tree,Vue3將 vnode 的更新性能調(diào)整為與動態(tài)內(nèi)容的數(shù)量相關。
其它
Vue3在編譯階段實現(xiàn)了對Slot的編譯優(yōu)化、事件偵聽函數(shù)的緩存優(yōu)化;Vue3重寫了diff算法。
語法API優(yōu)化
Vue3在語法上的一個大的變動主要是提供了Composition API,即組合式API。
在Vue2中,編寫組件本質是在編寫一個“包含了描述組件選項的對象”,被稱為Options API,即選項式API。
選項式API適合開發(fā)小型組件,選項內(nèi)容一目了然。對于包含多個邏輯關注點的大型組件來說,使用選項式API會導致一個邏輯關注點的代碼被分散到不同選項中。
組合式API的好處在于可以將邏輯關注點相關的代碼封裝到一個函數(shù)里。
邏輯復用優(yōu)化
在Vue2中,存在mixins這種邏輯復用的方式。它的缺點在于當一個組件混入多個來源的mixins后,會出現(xiàn)命名沖突和數(shù)據(jù)來源不清晰的問題。
在Vue3中,通過組合式函數(shù)解決了這一問題,組合式函數(shù)將可復用邏輯封裝成函數(shù)(按照規(guī)范通常以use作為函數(shù)名開頭),通常是返回一個對象。這是一種更靈活且更穩(wěn)定的做法,因為:
- 對于組合式函數(shù)來說,可以選擇性地向外暴露API;
- 對于使用地組件來說,解構返回的對象時,可以重命名避免命名沖突。
組合式API的其它好處:
- 更好的類型支持:組合式API都是函數(shù),類型更容易推導,不想選項式API所有的內(nèi)容都要通過
this聯(lián)系; - 組合式API對
tree-shaking比較友好,代碼也更容易壓縮。

浙公網(wǎng)安備 33010602011771號