亚洲视频一区在线播放_亚洲avav天堂av在线网毛片_久久久久亚洲AV无码去区首_亚洲AV综合色区无码二区偷拍

vue3編譯做了哪些優化

來源:php中文網 | 2022-12-19 18:04:15 |

本教程操作環境: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 過程如圖所示:

可以看到,因為這段代碼中只有一個動態節點,所以這里有很多 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

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

let currentBlock = nullfunction _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 如下:

此時生成的虛擬節點多出一個 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 和子節點進行全量的對比更新。圖解如下:

靜態提升

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

<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過程中極大地提高了性能。

以上就是vue3編譯做了哪些優化的詳細內容,更多請關注php中文網其它相關文章!

關鍵詞: Vue.js

亚洲视频一区在线播放_亚洲avav天堂av在线网毛片_久久久久亚洲AV无码去区首_亚洲AV综合色区无码二区偷拍

          国产亚洲一区二区三区四区| 中文字幕色av一区二区三区| 欧美色图片你懂的| 在线亚洲+欧美+日本专区| 欧美午夜免费电影| 欧美精品 日韩| 精品少妇一区二区| 国产午夜精品在线观看| 国产精品乱码久久久久久| 亚洲精品一二三| 日日骚欧美日韩| 国模冰冰炮一区二区| 成人免费精品视频| 国产午夜精品一区二区| 亚洲啪啪综合av一区二区三区| 亚洲一级不卡视频| 欧美日韩不卡视频| 久久嫩草精品久久久精品| 亚洲三级电影网站| 日本不卡免费在线视频| 国产精品 欧美精品| 久久蜜桃av一区精品变态类天堂 | 国产精品美女久久久久久久网站| 综合精品久久久| 色老头久久综合| 日韩欧美一二三四区| 欧美国产精品久久| 一区二区欧美国产| 国内精品嫩模私拍在线| 91蜜桃视频在线| 亚洲欧美乱综合| 欧美日韩一区不卡| 久久精品欧美日韩| 亚洲一级二级三级在线免费观看| 经典一区二区三区| 久久色成人在线| 亚洲自拍偷拍网站| 欧美一区午夜视频在线观看| 国产精品久久久一本精品| 天天综合色天天综合色h| 国产河南妇女毛片精品久久久| 国产日韩欧美一区二区三区乱码| 亚洲高清一区二区三区| 日韩欧美在线不卡| 亚洲欧美一区二区三区孕妇| 精品一区二区三区的国产在线播放 | 日韩高清欧美激情| 波多野结衣欧美| 亚洲免费观看高清完整版在线| 欧美日本国产视频| 中文字幕一区日韩精品欧美| 麻豆成人免费电影| 国产午夜久久久久| 欧美在线制服丝袜| 亚洲国产高清aⅴ视频| 日韩高清不卡一区二区| 91偷拍与自偷拍精品| 亚洲国产一区二区三区青草影视 | 亚洲三级在线观看| 国产乱码精品一区二区三区av| 亚洲国产精品av| 欧美日韩一二三| 亚洲欧美在线观看| 国产精品456| 亚洲男人的天堂av| 精品奇米国产一区二区三区| 亚洲国产精品尤物yw在线观看| 成人禁用看黄a在线| 一区二区三区高清在线| 欧美精品一区二区三区高清aⅴ | 亚洲综合一区在线| 成人免费毛片嘿嘿连载视频| 最新不卡av在线| 日韩一卡二卡三卡四卡| 亚洲一区二区高清| 2020国产成人综合网| 在线观看亚洲一区| 亚洲色图在线视频| 不卡视频一二三| 91国产福利在线| **性色生活片久久毛片| 国产99久久久国产精品潘金网站| 一区二区欧美视频| 国产婷婷色一区二区三区| 精品一区二区在线免费观看| 亚洲欧美日韩久久| 久久久亚洲精华液精华液精华液| 欧美a一区二区| 亚洲欧洲一区二区在线播放| 日韩欧美在线不卡| 免费xxxx性欧美18vr| 中文字幕日韩精品一区| 久久综合久久综合亚洲| 久久99热狠狠色一区二区| 亚洲欧美日韩国产成人精品影院| 久久亚洲综合色| 经典三级视频一区| 亚洲一区二区精品视频| 国产精品色在线观看| 成人视屏免费看| 欧美专区亚洲专区| 亚洲一卡二卡三卡四卡| 国产亚洲成年网址在线观看| 欧美一区二区高清| 青椒成人免费视频| 一区二区三区中文免费| 亚洲国产成人在线| 成人精品国产福利| 欧美精品色综合| 日本不卡视频在线| 亚洲激情自拍视频| 中文字幕一区二区三区四区| 99久久精品国产一区| 欧美高清视频www夜色资源网| 亚洲国产aⅴ成人精品无吗| 欧美激情在线观看视频免费| 亚洲精品一区二区三区影院| 国产精品小仙女| 欧美系列一区二区| 日韩 欧美一区二区三区| 一区二区国产视频| 亚洲免费在线播放| 国产精品全国免费观看高清| 久久综合资源网| 风间由美性色一区二区三区| 欧美日韩一级黄| 久久不见久久见免费视频7| 婷婷国产在线综合| 午夜欧美在线一二页| 樱桃国产成人精品视频| 亚洲三级理论片| 中文字幕一区二区三区不卡 | 国产偷国产偷亚洲高清人白洁| 精品国产亚洲一区二区三区在线观看| 国产在线播放一区三区四| 欧美中文字幕一二三区视频| 欧美aⅴ一区二区三区视频| 午夜精品视频在线观看| 亚洲成a人在线观看| 亚洲综合激情小说| 亚洲第四色夜色| 亚洲国产cao| 肉丝袜脚交视频一区二区| 亚洲国产精品一区二区www| 亚洲国产婷婷综合在线精品| 亚洲免费在线看| 亚洲自拍偷拍欧美| 亚洲精品欧美激情| 亚洲线精品一区二区三区八戒| 亚洲男人的天堂在线aⅴ视频| 亚洲精品国产无套在线观| 亚洲欧美国产77777| 亚洲综合视频在线| 亚洲伊人色欲综合网| 香蕉成人伊视频在线观看| 午夜婷婷国产麻豆精品| 日韩综合一区二区| 在线中文字幕一区二区| 经典三级在线一区| 91麻豆精品国产91久久久久久| 国产精品69久久久久水密桃| 日韩一区二区电影在线| av不卡免费电影| 国产日韩高清在线| 国产精品久久久久久久久免费丝袜 | 国产精品亚洲人在线观看| 日韩午夜在线影院| 99视频在线精品| 国产日韩精品一区二区三区| 中文字幕精品一区| 亚洲欧美日韩一区二区| 一区二区三区成人| 青娱乐精品视频| 欧美区一区二区三区| 成人av在线资源| 国产欧美日韩视频在线观看| 国产精品久久久久久久久免费相片 | 欧美国产日韩亚洲一区| 国产精品欧美一区喷水| 一区二区三区美女| 午夜婷婷国产麻豆精品| 国产中文一区二区三区| 欧美成人精品高清在线播放| 久久精品综合网| 亚洲精品久久久久久国产精华液| 亚洲图片欧美色图| 国产麻豆精品theporn| 日韩欧美高清在线| 国产欧美中文在线| 亚洲夂夂婷婷色拍ww47| 欧美午夜一区二区| 成人av手机在线观看| 国产精品久久网站| 亚洲成人你懂的| 国产福利一区在线观看| 久久久久久久久久久电影| 中文字幕一区二| 免费在线看成人av| 精品欧美乱码久久久久久| 国产精品对白交换视频|