成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網
最全最豐富的資訊網站

vue3編譯做了哪些優化

vue3編譯優化有:1、引入了 patchFlag,用來標記動態內容;在編譯過程中會根據不同的屬性類型打上不同的標識,從而實現了快速diff算法。2、Block Tree。3、靜態提升,是將靜態的節點或者屬性提升出去。4、預解析字符串化,當連續靜態節點超過10個時,會將靜態節點序列化為字符串。5、函數緩存;開啟cacheHandlers選項后,函數會被緩存起來,后續可直接使用。

vue3編譯做了哪些優化

本教程操作環境:windows7系統、vue3版,DELL G3電腦。

本文主要來分析 Vue3.0 編譯階段做的優化,在 patch 階段是如何利用這些優化策略來減少比對次數。 由于組件更新時依然需要遍歷該組件的整個 vnode 樹,比如下面這個模板:

<template>   <div id="container">     <p class="text">static text</p>     <p class="text">static text</p>     <p class="text">{{ message }}</p>     <p class="text">static text</p>     <p class="text">static text</p>   </div> </template>
登錄后復制

整個 diff 過程如圖所示:

vue3編譯做了哪些優化

可以看到,因為這段代碼中只有一個動態節點,所以這里有很多 diff 和遍歷其實都是不需要的,這就會導致 vnode 的性能跟模版大小正相關,跟動態節點的數量無關,當一些組件的整個模版內只有少量動態節點時,這些遍歷都是性能的浪費。對于上述例子,理想狀態只需要 diff 這個綁定 message 動態節點的 p 標簽即可。

Vue.js 3.0 通過編譯階段對靜態模板的分析,編譯生成了 Block tree

Block tree 是一個將模板基于動態節點指令切割的嵌套區塊,每個區塊內部的節點結構是固定的,而且每個區塊只需要以一個 Array 來追蹤自身包含的動態節點。借助 Block treeVue.js 將 vnode 更新性能由與模版整體大小相關提升為與動態內容的數量相關,這是一個非常大的性能突破。

PatchFlag

由于 diff 算法無法避免新舊虛擬 DOM 中無用的比較操作,Vue.js 3.0 引入了 patchFlag,用來標記動態內容。在編譯過程中會根據不同的屬性類型打上不同的標識,從而實現了快速 diff 算法。PatchFlags 的所有枚舉類型如下所示:

export const enum PatchFlags {   TEXT = 1, // 動態文本節點   CLASS = 1 << 1, // 動態class   STYLE = 1 << 2, // 動態style   PROPS = 1 << 3, // 除了class、style動態屬性   FULL_PROPS = 1 << 4, // 有key,需要完整diff   HYDRATE_EVENTS = 1 << 5, // 掛載過事件的   STABLE_FRAGMENT = 1 << 6, // 穩定序列,子節點順序不會發生變化   KEYED_FRAGMENT = 1 << 7, // 子節點有key的fragment   UNKEYED_FRAGMENT = 1 << 8, // 子節點沒有key的fragment   NEED_PATCH = 1 << 9, // 進行非props比較, ref比較   DYNAMIC_SLOTS = 1 << 10, // 動態插槽   DEV_ROOT_FRAGMENT = 1 << 11,    HOISTED = -1, // 表示靜態節點,內容變化,不比較兒子   BAIL = -2 // 表示diff算法應該結束 }
登錄后復制

Block Tree

vue3編譯做了哪些優化

左側的 template 經過編譯后會生成右側的 render 函數,里面有 _openBlock_createElementBlock_toDisplayString_createElementVNode(createVnode) 等輔助函數。

let currentBlock = null function _openBlock() {   currentBlock = [] // 用一個數組來收集多個動態節點 } function _createElementBlock(type, props, children, patchFlag) {   return setupBlock(createVnode(type, props, children, patchFlag)); }  export function createVnode(type, props, children = null, patchFlag = 0) {   const vnode = {     type,     props,     children,     el: null, // 虛擬節點上對應的真實節點,后續diff算法     key: props?.["key"],     __v_isVnode: true,     shapeFlag,     patchFlag    };   ...    if (currentBlock && vnode.patchFlag > 0) {     currentBlock.push(vnode);   }   return vnode; }  function setupBlock(vnode) {   vnode.dynamicChildren = currentBlock;   currentBlock = null;   return vnode; }  function _toDisplayString(val) {   return isString(val)     ? val     : val == null     ? ""     : isObject(val)     ? JSON.stringify(val)     : String(val); }
登錄后復制

此時生成的 vnode 如下:

vue3編譯做了哪些優化

此時生成的虛擬節點多出一個 dynamicChildren 屬性,里面收集了動態節點 span

節點 diff 優化策略:

我們之前分析過,在 patch 階段更新節點元素的時候,會執行 patchElement 函數,我們再來回顧一下它的實現:

const patchElement = (n1, n2) => { // 先復用節點、在比較屬性、在比較兒子   let el = n2.el = n1.el;   let oldProps = n1.props || {}; // 對象   let newProps = n2.props || {}; // 對象   patchProps(oldProps, newProps, el);    if (n2.dynamicChildren) { // 只比較動態元素     patchBlockChildren(n1, n2);   } else {     patchChildren(n1, n2, el); // 全量 diff   } }
登錄后復制

我們在前面組件更新的章節分析過這個流程,在分析子節點更新的部分,當時并沒有考慮到優化的場景,所以只分析了全量比對更新的場景。

而實際上,如果這個 vnode 是一個 Block vnode,那么我們不用去通過 patchChildren 全量比對,只需要通過 patchBlockChildren 去比對并更新 Block 中的動態子節點即可。 由此可以看出性能被大幅度提升,從 tree 級別的比對,變成了線性結構比對。

我們來看一下它的實現:

const patchBlockChildren = (n1, n2) => {   for (let i = 0; i < n2.dynamicChildren.length; i++) {     patchElement(n1.dynamicChildren[i], n2.dynamicChildren[i])   } }
登錄后復制

屬性 diff 優化策略:

接下來我們看一下屬性比對的優化策略:

const patchElement = (n1, n2) => { // 先復用節點、在比較屬性、在比較兒子   let el = n2.el = n1.el;   let oldProps = n1.props || {}; // 對象   let newProps = n2.props || {}; // 對象   let { patchFlag, dynamicChildren } = n2      if (patchFlag > 0) {     if (patchFlag & PatchFlags.FULL_PROPS) { // 對所 props 都進行比較更新       patchProps(el, n2, oldProps, newProps, ...)     } else {       // 存在動態 class 屬性時       if (patchFlag & PatchFlags.CLASS) {         if (oldProps.class !== newProps.class) {           hostPatchProp(el, 'class', null, newProps.class, ...)         }       }       // 存在動態 style 屬性時       if (patchFlag & PatchFlags.STYLE) {         hostPatchProp(el, 'style', oldProps.style, newProps.style, ...)       }              // 針對除了 style、class 的 props       if (patchFlag & PatchFlags.PROPS) {         const propsToUpdate = n2.dynamicProps!         for (let i = 0; i < propsToUpdate.length; i++) {           const key = propsToUpdate[i]           const prev = oldProps[key]           const next = newProps[key]           if (next !== prev) {             hostPatchProp(el, key, prev, next, ...)           }         }       }       if (patchFlag & PatchFlags.TEXT) { // 存在動態文本         if (n1.children !== n2.children) {           hostSetElementText(el, n2.children as string)         }       }      } else if (dynamicChildren == null) {       patchProps(el, n2, oldProps, newProps, ...)     }   } }  function hostPatchProp(el, key, prevValue, nextValue) {   if (key === 'class') { // 更新 class      patchClass(el, nextValue)   } else if (key === 'style') { // 更新 style     patchStyle(el, prevValue, nextValue)   } else if (/^on[^a-z]/.test(key)) {  // events  addEventListener     patchEvent(el, key, nextValue);   } else { // 普通屬性 el.setAttribute     patchAttr(el, key, nextValue);   } }  function patchClass(el, nextValue) {   if (nextValue == null) {     el.removeAttribute('class'); // 如果不需要class直接移除   } else {     el.className = nextValue   } }  function patchStyle(el, prevValue, nextValue = {}){   ... }  function patchAttr(el, key, nextValue){   ... }
登錄后復制

總結: vue3 會充分利用 patchFlagdynamicChildren 做優化。如果確定只是某個局部的變動,比如 style 改變,那么只會調用 hostPatchProp 并傳入對應的參數 style 做特定的更新(靶向更新);如果有 dynamicChildren,會執行 patchBlockChildren 做對比更新,不會每次都對 props 和子節點進行全量的對比更新。圖解如下:

vue3編譯做了哪些優化

靜態提升

靜態提升是將靜態的節點或者屬性提升出去,假設有以下模板:

<div>   <span>hello</span>    <span a=1 b=2>{{name}}</span>   <a><span>{{age}}</span></a> </div>
登錄后復制

編譯生成的 render 函數如下:

export function render(_ctx, _cache, $props, $setup, $data, $options) {   return (_openBlock(), _createElementBlock("div", null, [     _createElementVNode("span", null, "hello"),     _createElementVNode("span", {       a: "1",       b: "2"     }, _toDisplayString(_ctx.name), 1 /* TEXT */),     _createElementVNode("a", null, [       _createElementVNode("span", null, _toDisplayString(_ctx.age), 1 /* TEXT */)     ])   ])) }
登錄后復制

我們把模板編譯成 render 函數是這個醬紫的,那么問題就是每次調用 render 函數都要重新創建虛擬節點。

開啟靜態提升 hoistStatic 選項后

const _hoisted_1 = /*#__PURE__*/_createElementVNode("span", null, "hello", -1 /* HOISTED */) const _hoisted_2 = {   a: "1",   b: "2" }  export function render(_ctx, _cache, $props, $setup, $data, $options) {   return (_openBlock(), _createElementBlock("div", null, [     _hoisted_1,     _createElementVNode("span", _hoisted_2, _toDisplayString(_ctx.name), 1 /* TEXT */),     _createElementVNode("a", null, [       _createElementVNode("span", null, _toDisplayString(_ctx.age), 1 /* TEXT */)     ])   ])) }
登錄后復制

預解析字符串化

靜態提升的節點都是靜態的,我們可以將提升出來的節點字符串化。 當連續靜態節點超過 10 個時,會將靜態節點序列化為字符串。

假如有如下模板:

<div>   <span>static</span>   <span>static</span>   <span>static</span>   <span>static</span>   <span>static</span>   <span>static</span>   <span>static</span>   <span>static</span>   <span>static</span>   <span>static</span> </div>
登錄后復制

開啟靜態提升 hoistStatic 選項后

const _hoisted_1 = /*#__PURE__*/_createStaticVNode("<span>static</span><span>static</span><span>static</span><span>static</span><span>static</span><span>static</span><span>static</span><span>static</span><span>static</span><span>static</span>", 10) const _hoisted_11 = [  _hoisted_1]  export function render(_ctx, _cache, $props, $setup, $data, $options) {   return (_openBlock(), _createElementBlock("div", null, _hoisted_11)) }
登錄后復制

函數緩存

假如有如下模板:

<div @click="event => v = event.target.value"></div>
登錄后復制

編譯后:

const _hoisted_1 = ["onClick"]  export function render(_ctx, _cache, $props, $setup, $data, $options) {   return (_openBlock(), _createElementBlock("div", {     onClick: event => _ctx.v = event.target.value   }, null, 8 /* PROPS */, _hoisted_1)) }
登錄后復制

每次調用 render 的時候要創建新函數,開啟函數緩存 cacheHandlers 選項后,函數會被緩存起來,后續可以直接使用

export function render(_ctx, _cache, $props, $setup, $data, $options) {   return (_openBlock(), _createElementBlock("div", {     onClick: _cache[0] || (_cache[0] = event => _ctx.v = event.target.value)   })) }
登錄后復制

總結

以上幾點即為 Vuejs 在編譯階段做的優化,基于上面幾點,Vuejspatch 過程中極大地提高了性能。

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
久久久亚洲AV波多野结衣| 久久99国产精品久久99软件| 国产又黄又潮娇喘视频在线观看| 国产亚洲AV手机在线观看| 狠狠躁夜夜躁AV网站色| 久久久久久精品人妻免费网站| 老湿机香蕉久久久久久| 欧美日产欧美日产国产精品| 任你躁国产自任一区二区三区| 少妇被CAO高潮呻吟声| 午夜福利片手机在线播放| 亚洲乱码尤物193YW| 中文无码久久精品| 播放少妇的奶头出奶水的毛片| 国产成人精品日本亚洲专区不卡| 国产精品未满十八禁止观看| 精品人伦一区二区三区潘金莲| 狂性XXXX乱大交老女人| 欧洲美女黑人粗性暴交视频| 特黄大片又粗又大又暴| 亚洲国产AⅤ精品一区二区蜜桃 | 女角色翻白眼流口水流眼泪图片| 人妻一区二区三区高清AV专区| 无码国产偷倩在线播放老年人| 亚洲精品无码久久久久APP| 性欧美玩弄性少妇HD| 动漫人物桶动漫人物免费观看网站| 日韩午夜理论片 中文字幕| 天无日天天射天天视| 亚洲精品人成无码中文毛片| 99久久夜色精品国产网站| 乖别添了快放进来我想要| 激情男女高潮射精AV免费| 女人双腿搬开让男人桶| 无码高潮爽到爆的喷水视频| 亚洲中文字幕久久无码精品| 被多男摁住灌浓精| 黑人粗大与亚裔乱P视频| 女人被男人爽到呻吟的视频| 舔高中女生奶头内射视频| 野花韩国高清免费视频6| 成人片黄网站色大片免费观看AP| 国内精品国产三级国产AV| 女人被弄到高潮的免费视频| 无码人妻久久久一区二区三区免费 | 亚洲第一极品精品无码久久| AAAA级少妇高潮大片在线观看| 国产成人亚洲综合色影视| 久久无码中文字幕免费影院| 色欲蜜臀av无码久久浪潮一区| 亚洲欧美一区二区成人片婷婷| А√天堂8在线官网| 黑料社ZZTT.WIN免费观看| 欧美一性一乱一交一视频| 亚洲AV日韩AV无码污污网站| GRANSREMEDY老太太| 幻女FREE性俄罗斯毛片福| 人人妻人人爽人人澡人人| 亚洲精品乱码久久久久久| 波多野成人无码精品电影| 精品人妻一区二区三区浪潮在线| 日本肥老妇色XXXXX日本老妇| 亚洲人成网站在线在线观看| 顶级RAPPER潮水日本| 老熟女HDXX中国老熟女| 玩50岁四川熟女大白屁股直播| 12一14性XXXXX国产| 国产内射老熟女AAAA∵| 欧美人禽猛交乱配1| 亚洲精品AⅤ中文字幕乱码| 岛国无码AⅤ片在线观看| 老太性开放BBWBBWBBW| 小洞饿了想吃大香肠| www高潮无码免费看| 久久精品国产自清天天线| 铜铜铜铜铜铜铜铜铜好多深| 99久久精品无码一区二区毛片| 激情偷乱人伦小说视频最新章节| 日韩码一码二码三码区别| 中文字幕无码视频手机免费看| 国产综合精品一区二区三区| 日本最新免费二区| 做AJ的姿势教程大全图| 精品国产乱码久久久久久浪潮小说 | 九九真实偷窥短视频| 无码动漫性爽XO视频在线观看不| CHINESE国产XXXX实拍| 久久久久久精品精品免费| 性XXXX欧美老妇506070| 刺激战场老阿姨是谁啊| 男男车车CP视频| 亚洲性日韩精品一区二区三区| 国产精品一线二线三线| 日韩免费无码人妻波多野| 69美女黑人做受XXXXXⅩ| 久久久WWW成人免费精品| 亚洲AV日韩AⅤ永久无码| 国产成人免费无码AV在线播放| 人人妻人人澡人人爽不卡视频| 中文成人无码精品久久久不卡免费| 娇妻被猛男老外玩三PAV| 无码精品人成人片在线观看| 成人免费无码大片A毛片抽搐| 欧美 日韩 国产 成人 在线观 | 久久久久无码精品国产| 亚洲国产成人精品青青草原| 国产精品亚洲А∨无码播放不卡| 色老头在线一区二区三区| おまえの母亲をだます怎么读| 免费极品AV一视觉盛宴| 日本打扑克啪啪超爽网站| 69ZXX少妇内射无码| 毛片无码中文字幕| 亚洲综合AV色婷婷国产野外| 精品人妻中文无码AV在线| 亚洲AV无码一期二期三期少妇| 国产精品白丝JK白祙喷水视频| 搡老女人老妇老熟女hd| 波多野结衣av电影在线观看| 欧美日韩中文国产一区发布| 9999久久久久精品无码| 免费无码专区毛片高潮喷水| 中国国语毛片免费观看视频| 久久综合激的五月天的歌词| 亚洲中文字幕无码永久在线不卡 | 亚洲乱妇熟女爽到高潮| 果冻传媒剧国产剧在线看| 亚洲AⅤ无码牛牛影视| 国产无夜激无码AV毛片| 无码中文亚洲AV影音先锋无码| 国产成人精品日本亚洲成熟| 无码精品人妻一区二区三区影院| 国产成人无码一区二区三区| 无码AV最新高清无码专区| 国产很色很黄很大爽的视频| 无码人妻久久1区2区3区| 国产无遮挡又黄又爽无VIP| 亚洲AV无码成人精品区日韩| 狠狠色欧美亚洲狠狠色WWW| 亚洲乱色伦图片区小说| 久久精品熟女亚洲AV麻豆网站| 一级伦奷片高潮无码看了5| 浪荡女天天不停挨CAO日常视频| 玉蒲团之极乐宝鉴| 男女性杂交内射妇女BBWXZ| ASSFREE疯狂老妇熟女| 人妻少妇精品无码专区二区| 成人av在线网站| 天天躁日日躁狠狠躁AV中文| 国产美女裸体丝袜喷水视频| 亚洲AV伊人久久青青草原| 久久精品99国产精品蜜桃| 在线视频夫妻内射| 欧美亚洲综合另类色妞网| 丁香婷婷在线成人播放视频| 无码中文字幕日韩专区| 教室停电了校草挺进我体内| 一边下奶一边吃面膜视频讲解| 免费观看18禁欲无遮挡奶水下 | 亚洲影院丰满少妇中文字幕无码| 老头挺进娇妻身体| HD老熟女BBN老淑女| 少妇无码一区二区二三区| 国产亚洲曝欧美不卡精品| 亚洲熟妇色XXXXXX爽| 免费无遮挡色视频网站| 成视频年人黄网站免费视频| 西西人体444WWW高清大但| 久久精品久久电影免费| AⅤ中文字幕不卡在线无码| 牲交A欧美牲交AⅤ免费一| 国产香蕉97碰碰视频VA碰碰看| 亚洲综合色成在线观看| 欧美性色欧美A在线播放| 国产成人无码18禁午夜福利免费| 亚洲成a人片在线观看无码专区| 久久亚洲国产成人影院| 宝宝锕~进去就不痛了在线观看| 无码H黄肉动漫在线观看999| 久久精品成人无码观看免费| Chinese国产男男视频观看| 天堂√在线中文最新版8| 精品国产AⅤ一区二区三区V视界| 18禁止午夜福利体验区| 日韩欧美人妻一区二区三区| 国内精品乱码卡一卡2卡三卡新区| 在公交车上弄到高C了| 日日噜噜夜夜狠狠视频| 激情无码人妻又粗又大中国人| 2021自拍偷在线精品自拍偷| 丝瓜秋葵草莓香蕉榴莲绿| 久久99精品久久久久久HB无码| AV无码不卡一区二区三区| 无套内谢孕妇毛片免费看看| 狂猛欧美激情性XXXX在线观看| 刺激的乱亲小说43部分阅读| 亚洲色一色鲁一鲁鲁| 日韩精品无码免费专区网站 | 亚洲欧美偷国产日韩| 日本强伦姧人妻完视频正版|