1. 程式人生 > 前端設計 >Vue3.0 效能優化及新特性深度解析

Vue3.0 效能優化及新特性深度解析

最近,Vue作者尤雨溪在B站的演講中分享了Vue3.0的六大亮點:

  • 效能
  • Tree-shaking 支援
  • Composition API
  • Fragment、Teleport、Suspense
  • 更好的 TS 支援
  • 自定義渲染API

編譯時對VDom的效能優化

PatchFlag

首先看下面這個案例,模版中有三個P標籤,其中只有最後一個P標籤的TEXT部分是動態的

在之前的VDOM中,如果msg值發生改變,整個模版中的所有元素都需要重新渲染。但在Vue3.0中,在這個模版編譯時,編譯器會在動態標籤末尾加上 /* Text*/ PatchFlag。只能帶patchFlag 的 Node 才被認為是動態的元素,會被追蹤屬性的修改。並且 PatchFlag 會標識動態的屬性型別有哪些,比如這裡 的TEXT 表示只有節點中的文字是動態的。

每一個Block中的節點,就算很深,也是直接跟Block一層繫結的,可以直接跳轉到動態節點而不需要逐個逐層遍歷。

既有VDOM的靈活性,又有效能保證。

hoistStatic 靜態節點提升

當使用hoistStatic時,所有 靜態的節點都被提升到render方法之外。這意味著,他們只會在應用啟動的時候被建立一次,而後隨著每次的渲染被不停的複用。

在大型應用中對於記憶體有很大的優化。

cacheHandler 事件監聽快取

正常情況下,當繫結一個事件:

<div>
  <p @click="handleClick">靜態程式碼</p>
</div>
複製程式碼

模版會被編譯為

export function render(_ctx,_cache) {
  return (_openBlock(),_createBlock("div",null,[
    _createVNode("p",{ onClick: _ctx.handleClick },"靜態程式碼",8 /* PROPS */,["onClick"])
  ]))
}
複製程式碼

其中事件會每次從全域性上下文中獲取。而當開啟了cacheHandler之後

export function render(_ctx,{
      onClick: _cache[1] || (_cache[1] = ($event,...args
) =>
(_ctx.handleClick($event,...args))) },"靜態程式碼") ])) } 複製程式碼

編輯器會為你動態建立一個行內函數,行內函數裡面再去飲用當前元件上最新的handler。之後編輯器會將行內函數快取。每次重新渲染時如果事件處理器沒有變,就會使用快取中的事件處理而不會重新獲取事件處理器。這個節點就可以被看作是一個靜態的節點。這種優化更大的作用在於當其作用域元件時,之前每次重新渲染都會導致元件的重新渲染,在通過handler快取之後,不會導致元件的重新渲染了。

SSR 服務端渲染

當開啟SSR了之後,如果我們模版中有一些靜態標籤,這些靜態標籤會被直接轉化成文字。

其中的動態繫結依然是一個單獨的字串內嵌進去。這個效能肯定比React 轉成VDOM在專為HTML快很多。

StaticNode 靜態節點

剛才提到在SSR中靜態的節點會被轉化為純字串。如果在客戶端,當靜態節點巢狀足夠多的時候,VUE編譯器也會將VDOM轉化為純字串的HTML。即 StaticNode。

通過這些操作,我們可以看下,跟vue2比可以快一倍以上,記憶體佔用可以小一倍以上。

Tree Shaking

因為ES6模組是靜態引用的,所以我們可以在編譯時正確的判斷到底載入了哪些程式碼。對程式碼全域性做一個分析,找到那些沒用被用到的模組、函式、變數,並把這些去掉。
複製程式碼

當使用一個 bundle (webpack etc.)的時候,預設會加上 TreeShaking。Vue 3.0 中沒有被用到的模組可以不被打包到編譯後的檔案中,被 TreeShake 掉。當只有一個HelloWorld的時候 Vue3打包後 13.5kb。所有的元件全部載入進來時是 22.5kb

Composition API

隨著Vue元件的增大,元件內程式碼變得越來越難以理解和維護。其中的一些可以複用的程式碼很難被抽離出來。同時 Vue2.0還缺少 TS支援。在Vue2中,邏輯概念(功能)被管理在元件中,但是功能和元件並不是一對一關係。一個功能可以被多個元件使用同時一個元件可以有多個功能。在Vue中,一個功能可能需要依賴多個Options(components、props、data、computed、methods及生命週期方法)。

在 Composition API中提供可 setup 方法。以一個有搜尋功能和 排序功能元件為例:

<script>
export default {
    setup() {
    
    }
}

function useSearch() {
    return { 
    ...useSearch(),...useSorting()
    }
}

function useSorting() {
    
}

</script>
複製程式碼

Vue2 中的程式碼複用

Mixin

在Vue2中有幾種方式可以複用程式碼,其中之一就是 Mixins。

  • Mixins可以實現組織功能
  • 容易發生衝突
  • 很難說明依賴關係
  • 程式碼不容易複用

Mixin 工廠

  • 可以方便複用
  • 明確的依賴關係
  • 弱名稱空間
  • 隱性的屬性新增

Scoped Slots

  • 解決了 Mixin 的問題
  • 增加了層級關係導致更難以理解
  • 很多配置資訊
  • 靈活性更少
  • 效能較差

核心 API

  • reactive
  • ref
  • computed
  • readonly
  • watchEffect
  • watch
  • Lifecycle Hooks

Fragments

Vue3中不在要求模版的跟節點必須是隻能有一個節點。跟節點和和render函式返回的可以是純文字、陣列、單個節點,如果是陣列,會自動轉化為 Fragments。

Teleport

對標 React Portal。可以做一些關於響應式的設計,如果螢幕寬度比較寬的時候,加入某些元素,螢幕變窄後移除。

Suspense

等待巢狀的非同步依賴。再把一個巢狀的元件樹渲染到頁面上之前,先在記憶體中進行渲染,並記錄所有的存在非同步依賴的元件。只有所有的非同步依賴全部被resolve之後,才會把整個書渲染到dom中。當你的元件中有一個 async的 setup函式,這個元件可以被看作是一個Async Component,只有當這個元件被Resolve之後,再把整個樹渲染出來

  • async setup()
  • Async Component

Typescript

Vue3原始碼使用 TS重寫,但不意味著vue3的專案也要使用TS。但Vue3會對 TS有更好的支援

  • 支援 TSX
  • 支援 Class component
  • 程式碼會變大一些

參考資料