1. 程式人生 > >Vue3教程:Vue 3.x 快在哪裡?

Vue3教程:Vue 3.x 快在哪裡?

人云亦云,並不會讓你變得有多優秀,而會讓你越來越隨大流。 當你和別的開發在聊到 Vue 3.0 版本釋出,有哪些亮點時,你的答案之一肯定有“它變得更快了,效能上快了 1.2 ~ 2倍”。 那麼我就想問你,是什麼讓 Vue 變快了,尤大已經在 beta 版的線上直播上告訴了我們答案。 ![](https://img2020.cnblogs.com/blog/859549/202012/859549-20201206214408962-551563995.png) ## PatchFlag(靜態標記) Vue 2.x 中的虛擬 DOM 是全量對比的模式,而到了 Vue 3.0 開始,新增了靜態標記(PatchFlag)。 在更新前的節點進行對比的時候,只會去對比帶有靜態標記的節點。並且 PatchFlag 列舉定義了十幾種類型,用以更精確的定位需要對比節點的型別。下面我們通過圖文例項分析這個對比的過程。 假設我們有下面一段程式碼: ```html

老八食堂

{{ message }}

``` 在 Vue 2.x 的全量對比模式下,如下圖所示: ![](https://img2020.cnblogs.com/blog/859549/202012/859549-20201206214419887-948117406.png) 通過上圖,我們發現,Vue 2.x 的 diff 演算法將每個標籤都比較了一次,最後發現帶有 `{{ message }}` 變數的標籤是需要被更新的標籤,顯然這還有優化的空間。 在 Vue 3.0 中,對 diff 演算法進行了優化,在建立虛擬 DOM 時,根據 DOM 內容是否會發生變化,而給予相對應型別的靜態標記(PatchFlag),如下圖所示: ![](https://img2020.cnblogs.com/blog/859549/202012/859549-20201206214426765-1922727971.png) 觀察上圖,不難發現檢視的更新只對帶有 flag 標記的標籤進行了對比(diff),所以只進行了 1 次比較,而相同情況下,Vue 2.x 則進行了 3 次比較。這便是 Vue 3.0 比 Vue2.x 效能好的第一個原因。 我們再通過把模板程式碼轉譯成虛擬 DOM,來驗證我們上述的分析是否正確。我們可以開啟模板轉化[網站](https://vue-next-template-explorer.netlify.app/),對上述程式碼進行轉譯: ![](https://img2020.cnblogs.com/blog/859549/202012/859549-20201206214438254-2131400225.png) 上圖藍色框內為轉譯後的虛擬 DOM 節點,第一個 P 標籤為寫死的靜態文字,而第二個 P 標籤則為繫結的變數,所以打上了 1 標籤,代表的是 TEXT(文字),標記列舉型別如下: ```javascript export const enum PatchFlags { TEXT = 1,// 動態的文字節點 CLASS = 1 << 1, // 2 動態的 class STYLE = 1 << 2, // 4 動態的 style PROPS = 1 << 3, // 8 動態屬性,不包括類名和樣式 FULL_PROPS = 1 << 4, // 16 動態 key,當 key 變化時需要完整的 diff 演算法做比較 HYDRATE_EVENTS = 1 << 5, // 32 表示帶有事件監聽器的節點 STABLE_FRAGMENT = 1 << 6, // 64 一個不會改變子節點順序的 Fragment KEYED_FRAGMENT = 1 << 7, // 128 帶有 key 屬性的 Fragment UNKEYED_FRAGMENT = 1 << 8, // 256 子節點沒有 key 的 Fragment NEED_PATCH = 1 << 9, // 512 DYNAMIC_SLOTS = 1 << 10, // 動態 solt HOISTED = -1, // 特殊標誌是負整數表示永遠不會用作 diff BAIL = -2 // 一個特殊的標誌,指代差異演算法 } ``` ## hoistStatic(靜態提升) 我們平時在開發過程中寫函式的時候,定義一些寫死的變數時,都會將變數提升出去定義,如下所示: ```javascript const PAGE_SIZE = 10 function getData () { $.get('/data', { data: { page: PAGE_SIZE }, ... }) } ``` 諸如上述程式碼,如果將 `PAGE_SIZE = 10` 寫在 `getData` 方法內,每次呼叫 `getData` 都會重新定義一次變數。 Vue 3.0 在這方面也做了同樣的優化,繼續用我們上一個例子寫的程式碼,觀察編譯之後的虛擬 DOM 結構,如下所示: 沒有做靜態提升前: ![](https://img2020.cnblogs.com/blog/859549/202012/859549-20201206214448632-1637641849.png) 選擇 Option 下的 `hoistStatic`: ![](https://img2020.cnblogs.com/blog/859549/202012/859549-20201206214455397-752448612.png) 靜態提升後: ![](https://img2020.cnblogs.com/blog/859549/202012/859549-20201206214504061-859678392.png) 細心的同學會發現, `老八食堂` 被提到了 `render` 函式外,每次渲染的時候只要取 `_hoisted_1` 變數便可。認真看文章的同學又會發現一個細節, `_hoisted_1` 被打上了 `PatchFlag` ,靜態標記值為 -1 ,特殊標誌是負整數表示永遠不會用作 Diff。也就是說被打上 -1 標記的,將不在參與 Diff 演算法,這又提升了 Vue 的效能。 ## cacheHandler(事件監聽快取) 預設情況下 `@click` 事件被認為是動態變數,所以每次更新檢視的時候都會追蹤它的變化。但是正常情況下,我們的 `@click` 事件在檢視渲染前和渲染後,都是同一個事件,基本上不需要去追蹤它的變化,所以 Vue 3.0 對此作出了相應的優化叫事件監聽快取,我們在上述程式碼中加一段: ```html

屋裡一giao

``` 編譯後如下圖所示(還未開啟 cacheHandler): ![](https://img2020.cnblogs.com/blog/859549/202012/859549-20201206214512484-1197323438.png) 在未開啟事件監聽快取的情況下,我們看到這串程式碼編譯後被靜態標記為 8,之前講解過被靜態標記的標籤就會被拉去做比較,而靜態標記 8 對應的是“動態屬性,不包括類名和樣式”。 `@click` 被認為是動態屬性,所以我們需要開啟 Options 下的 `cacheHandler` 屬性,如下圖所示: ![](https://img2020.cnblogs.com/blog/859549/202012/859549-20201206214522949-5448451.png) 細心的同學又會發現,開啟 `cacheHandler` 之後,編譯後的程式碼已經沒有靜態標記(PatchFlag),也就表明圖中 P 標籤不再被追蹤比較變化,進而提升了 Vue 的效能。 ## SSR 服務端渲染 當你在開發中使用 SSR 開發時,Vue 3.0 會將靜態標籤直接轉化為文字,相比 React 先將 jsx 轉化為虛擬 DOM,再將虛擬 DOM 轉化為 HTML,Vue 3.0 已經贏了。 ![ssr.jpg](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0332824ca4e84aa481cc7448ec25ae41~tplv-k3u1fbpfcp-zoom-1.image) ## StaticNode(靜態節點) 上述 SSR 服務端渲染,會將靜態標籤直接轉化為文字。在客戶端渲染的時候,只要標籤巢狀得足夠多,編譯時也會將其轉化為 HTML 字串,如下圖所示: ![](https://img2020.cnblogs.com/blog/859549/202012/859549-20201206214539072-1721881511.png) >
需要開啟 Options 下的 hoistStatic ## 總結 以上便是 Vue3.0 在編譯時針對虛擬 DOM 的效能優化,這使得 Vue 3.0 在效能上是 Vue 2.x 的 1.2~2倍。 建立了一個 Vue3 的學習倉庫 [vue3-examples](https://github.com/newbee-ltd/vue3-examples),倉庫地址:[https://github.com/newbee-ltd/vue3-examples](https://github.com/newbee-ltd/vue3-examples),此倉庫將不定期更新各種 Vue3.0 相關的知識及各種整合 Demo 及 Vue3 使用小技巧,大家可以關注一下,有什麼建議也歡迎大家給我留言。 [![](https://img2020.cnblogs.com/blog/859549/202012/859549-20201206214549199-465911387.png)](https://github.com/newbee-ltd/vue3-examples) >
除註明轉載/出處外,皆為作者原創,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結,否則保留追究法律責任的