2.Vue3.0 性能提升主要是通过哪几方面体现的?
一、編譯階段
回顧Vue2,我們知道每個組件實例都對應(yīng)一個?watcher?實例,它會在組件渲染的過程中把用到的數(shù)據(jù)property記錄為依賴,當(dāng)依賴發(fā)生改變,觸發(fā)setter,則會通知watcher,從而使關(guān)聯(lián)的組件重新渲染
試想一下,一個組件結(jié)構(gòu)如下圖
<template><div?id="content"><p?class="text">靜態(tài)文本</p><p?class="text">靜態(tài)文本</p><p?class="text">{{?message?}}</p><p?class="text">靜態(tài)文本</p>...<p?class="text">靜態(tài)文本</p></div> </template>可以看到,組件內(nèi)部只有一個動態(tài)節(jié)點,剩余一堆都是靜態(tài)節(jié)點,所以這里很多?diff?和遍歷其實都是不需要的,造成性能浪費(fèi)
因此,Vue3在編譯階段,做了進(jìn)一步優(yōu)化。主要有如下:
-
diff算法優(yōu)化
-
靜態(tài)提升
-
事件監(jiān)聽緩存
-
SSR優(yōu)化
diff算法優(yōu)化
vue3在diff算法中相比vue2增加了靜態(tài)標(biāo)記
關(guān)于這個靜態(tài)標(biāo)記,其作用是為了會發(fā)生變化的地方添加一個flag標(biāo)記,下次發(fā)生變化的時候直接找該地方進(jìn)行比較
下圖這里,已經(jīng)標(biāo)記靜態(tài)節(jié)點的p標(biāo)簽在diff過程中則不會比較,把性能進(jìn)一步提高
關(guān)于靜態(tài)類型枚舉如下
export?const?enum?PatchFlags?{TEXT?=?1,//?動態(tài)的文本節(jié)點CLASS?=?1?<<?1,??//?2?動態(tài)的?classSTYLE?=?1?<<?2,??//?4?動態(tài)的?stylePROPS?=?1?<<?3,??//?8?動態(tài)屬性,不包括類名和樣式FULL_PROPS?=?1?<<?4,??//?16?動態(tài)?key,當(dāng)?key?變化時需要完整的?diff?算法做比較HYDRATE_EVENTS?=?1?<<?5,??//?32?表示帶有事件監(jiān)聽器的節(jié)點STABLE_FRAGMENT?=?1?<<?6,???//?64?一個不會改變子節(jié)點順序的?FragmentKEYED_FRAGMENT?=?1?<<?7,?//?128?帶有?key?屬性的?FragmentUNKEYED_FRAGMENT?=?1?<<?8,?//?256?子節(jié)點沒有?key?的?FragmentNEED_PATCH?=?1?<<?9,???//?512DYNAMIC_SLOTS?=?1?<<?10,??//?動態(tài)?soltHOISTED?=?-1,??//?特殊標(biāo)志是負(fù)整數(shù)表示永遠(yuǎn)不會用作?diffBAIL?=?-2?//?一個特殊的標(biāo)志,指代差異算法 }靜態(tài)提升
Vue3中對不參與更新的元素,會做靜態(tài)提升,只會被創(chuàng)建一次,在渲染時直接復(fù)用
這樣就免去了重復(fù)的創(chuàng)建節(jié)點,大型應(yīng)用會受益于這個改動,免去了重復(fù)的創(chuàng)建操作,優(yōu)化了運(yùn)行時候的內(nèi)存占用
<span>你好</span><div>{{?message?}}</div>沒有做靜態(tài)提升之前
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?*/)) }做了靜態(tài)提升之后
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靜態(tài)內(nèi)容_hoisted_1被放置在render?函數(shù)外,每次渲染的時候只要取?_hoisted_1?即可
同時?_hoisted_1?被打上了?PatchFlag?,靜態(tài)標(biāo)記值為 -1 ,特殊標(biāo)志是負(fù)整數(shù)表示永遠(yuǎn)不會用于 Diff
事件監(jiān)聽緩存
默認(rèn)情況下綁定事件行為會被視為動態(tài)綁定,所以每次都會去追蹤它的變化
<div><button @click = 'onClick'>點我</button> </div>沒開啟事件監(jiān)聽器緩存
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?//動態(tài)屬性,但不包含類名和樣式])) })開啟事件偵聽器緩存后
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)))},?"點我")])) }上述發(fā)現(xiàn)開啟了緩存后,沒有了靜態(tài)標(biāo)記。也就是說下次diff算法的時候直接使用
SSR優(yōu)化
當(dāng)靜態(tài)內(nèi)容大到一定量級時候,會用createStaticVNode方法在客戶端去生成一個static node,這些靜態(tài)node,會被直接innerHtml,就不需要創(chuàng)建對象,然后根據(jù)對象渲染
div><div><span>你好</span></div>...??//?很多個靜態(tài)屬性<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
任何一個函數(shù),如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}} });三、響應(yīng)式系統(tǒng)
vue2中采用?defineProperty來劫持整個對象,然后進(jìn)行深度遍歷所有屬性,給每個屬性添加getter和setter,實現(xiàn)響應(yīng)式
vue3采用proxy重寫了響應(yīng)式系統(tǒng),因為proxy可以對整個對象進(jìn)行監(jiān)聽,所以不需要深度遍歷
-
可以監(jiān)聽動態(tài)屬性的添加
-
可以監(jiān)聽到數(shù)組的索引和數(shù)組length屬性
-
可以監(jiān)聽刪除屬性
關(guān)于這兩個 API 具體的不同,我們下篇文章會進(jìn)行一個更加詳細(xì)的介紹
總結(jié)
以上是生活随笔為你收集整理的2.Vue3.0 性能提升主要是通过哪几方面体现的?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: nginx动静分离和资源隔离的网站搭建
- 下一篇: vue实现跑马灯抽奖