2.Vue3.0 性能提升主要是通过哪几方面体现的?
一、編譯階段
回顧Vue2,我們知道每個組件實例都對應一個?watcher?實例,它會在組件渲染的過程中把用到的數據property記錄為依賴,當依賴發生改變,觸發setter,則會通知watcher,從而使關聯的組件重新渲染
試想一下,一個組件結構如下圖
<template><div?id="content"><p?class="text">靜態文本</p><p?class="text">靜態文本</p><p?class="text">{{?message?}}</p><p?class="text">靜態文本</p>...<p?class="text">靜態文本</p></div> </template>可以看到,組件內部只有一個動態節點,剩余一堆都是靜態節點,所以這里很多?diff?和遍歷其實都是不需要的,造成性能浪費
因此,Vue3在編譯階段,做了進一步優化。主要有如下:
-
diff算法優化
-
靜態提升
-
事件監聽緩存
-
SSR優化
diff算法優化
vue3在diff算法中相比vue2增加了靜態標記
關于這個靜態標記,其作用是為了會發生變化的地方添加一個flag標記,下次發生變化的時候直接找該地方進行比較
下圖這里,已經標記靜態節點的p標簽在diff過程中則不會比較,把性能進一步提高
關于靜態類型枚舉如下
export?const?enum?PatchFlags?{TEXT?=?1,//?動態的文本節點CLASS?=?1?<<?1,??//?2?動態的?classSTYLE?=?1?<<?2,??//?4?動態的?stylePROPS?=?1?<<?3,??//?8?動態屬性,不包括類名和樣式FULL_PROPS?=?1?<<?4,??//?16?動態?key,當?key?變化時需要完整的?diff?算法做比較HYDRATE_EVENTS?=?1?<<?5,??//?32?表示帶有事件監聽器的節點STABLE_FRAGMENT?=?1?<<?6,???//?64?一個不會改變子節點順序的?FragmentKEYED_FRAGMENT?=?1?<<?7,?//?128?帶有?key?屬性的?FragmentUNKEYED_FRAGMENT?=?1?<<?8,?//?256?子節點沒有?key?的?FragmentNEED_PATCH?=?1?<<?9,???//?512DYNAMIC_SLOTS?=?1?<<?10,??//?動態?soltHOISTED?=?-1,??//?特殊標志是負整數表示永遠不會用作?diffBAIL?=?-2?//?一個特殊的標志,指代差異算法 }靜態提升
Vue3中對不參與更新的元素,會做靜態提升,只會被創建一次,在渲染時直接復用
這樣就免去了重復的創建節點,大型應用會受益于這個改動,免去了重復的創建操作,優化了運行時候的內存占用
<span>你好</span><div>{{?message?}}</div>沒有做靜態提升之前
export?function?render(_ctx,?_cache,?$props,?$setup,?$data,?$options)?{return?(_openBlock(),?_createBlock(_Fragment,?null,?[_createVNode("span",?null,?"你好"),_createVNode("div",?null,?_toDisplayString(_ctx.message),?1?/*?TEXT?*/)],?64?/*?STABLE_FRAGMENT?*/)) }做了靜態提升之后
const?_hoisted_1?=?/*#__PURE__*/_createVNode("span",?null,?"你好",?-1?/*?HOISTED?*/)export?function?render(_ctx,?_cache,?$props,?$setup,?$data,?$options)?{return?(_openBlock(),?_createBlock(_Fragment,?null,?[_hoisted_1,_createVNode("div",?null,?_toDisplayString(_ctx.message),?1?/*?TEXT?*/)],?64?/*?STABLE_FRAGMENT?*/)) }//?Check?the?console?for?the?AST靜態內容_hoisted_1被放置在render?函數外,每次渲染的時候只要取?_hoisted_1?即可
同時?_hoisted_1?被打上了?PatchFlag?,靜態標記值為 -1 ,特殊標志是負整數表示永遠不會用于 Diff
事件監聽緩存
默認情況下綁定事件行為會被視為動態綁定,所以每次都會去追蹤它的變化
<div><button @click = 'onClick'>點我</button> </div>沒開啟事件監聽器緩存
export?const?render?=?/*#__PURE__*/_withId(function?render(_ctx,?_cache,?$props,?$setup,?$data,?$options)?{return?(_openBlock(),?_createBlock("div",?null,?[_createVNode("button",?{?onClick:?_ctx.onClick?},?"點我",?8?/*?PROPS?*/,?["onClick"])//?PROPS=1<<3,//?8?//動態屬性,但不包含類名和樣式])) })開啟事件偵聽器緩存后
export?function?render(_ctx,?_cache,?$props,?$setup,?$data,?$options)?{return?(_openBlock(),?_createBlock("div",?null,?[_createVNode("button",?{onClick:?_cache[1]?||?(_cache[1]?=?(...args)?=>?(_ctx.onClick(...args)))},?"點我")])) }上述發現開啟了緩存后,沒有了靜態標記。也就是說下次diff算法的時候直接使用
SSR優化
當靜態內容大到一定量級時候,會用createStaticVNode方法在客戶端去生成一個static node,這些靜態node,會被直接innerHtml,就不需要創建對象,然后根據對象渲染
div><div><span>你好</span></div>...??//?很多個靜態屬性<div><span>{{?message?}}</span></div> </div>編譯后
import?{?mergeProps?as?_mergeProps?}?from?"vue" import?{?ssrRenderAttrs?as?_ssrRenderAttrs,?ssrInterpolate?as?_ssrInterpolate?}?from?"@vue/server-renderer"export?function?ssrRender(_ctx,?_push,?_parent,?_attrs,?$props,?$setup,?$data,?$options)?{const?_cssVars?=?{?style:?{?color:?_ctx.color?}}_push(`<div${_ssrRenderAttrs(_mergeProps(_attrs,?_cssVars))}><div><span>你好</span>...<div><span>你好</span><div><span>${_ssrInterpolate(_ctx.message)}</span></div></div>`) }二、源碼體積
相比Vue2,Vue3整體體積變小了,除了移出一些不常用的API,再重要的是Tree shanking
任何一個函數,如ref、reavtived、computed等,僅僅在用到的時候才打包,沒用到的模塊都被搖掉,打包的整體體積變小
import?{?computed,?defineComponent,?ref?}?from?'vue'; export?default?defineComponent({setup(props,?context)?{const?age?=?ref(18)let?state?=?reactive({name:?'test'})const?readOnlyAge?=?computed(()?=>?age.value++)?//?19return?{age,state,readOnlyAge}} });三、響應式系統
vue2中采用?defineProperty來劫持整個對象,然后進行深度遍歷所有屬性,給每個屬性添加getter和setter,實現響應式
vue3采用proxy重寫了響應式系統,因為proxy可以對整個對象進行監聽,所以不需要深度遍歷
-
可以監聽動態屬性的添加
-
可以監聽到數組的索引和數組length屬性
-
可以監聽刪除屬性
關于這兩個 API 具體的不同,我們下篇文章會進行一個更加詳細的介紹
總結
以上是生活随笔為你收集整理的2.Vue3.0 性能提升主要是通过哪几方面体现的?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: nginx动静分离和资源隔离的网站搭建
- 下一篇: 看了第一句,有人就哭了?