Jadual Kandungan
PatchFlag
Pokok Sekat
Strategi pengoptimuman perbezaan nod:
Strategi pengoptimuman perbezaan atribut:
静态提升
预解析字符串化
函数缓存
总结
Rumah hujung hadapan web Soal Jawab bahagian hadapan Apakah pengoptimuman yang telah dilakukan dalam kompilasi vue3?

Apakah pengoptimuman yang telah dilakukan dalam kompilasi vue3?

Dec 19, 2022 pm 06:05 PM
hujung hadapan vue.js

Pengoptimuman kompilasi Vue3 termasuk: 1. PatchFlag diperkenalkan untuk menandakan kandungan dinamik semasa proses penyusunan, label yang berbeza akan ditanda mengikut jenis atribut yang berbeza, sekali gus merealisasikan algoritma perbezaan pantas. 2. Pokok Blok. 3. Promosi statik adalah untuk mempromosikan nod atau atribut statik. 4. Pre-parsing stringification, apabila terdapat lebih daripada 10 nod statik berturut-turut, nod statik akan bersiri menjadi rentetan. 5. Cache fungsi; selepas menghidupkan pilihan CacheHandlers, fungsi akan dicache dan boleh digunakan terus kemudian.

Apakah pengoptimuman yang telah dilakukan dalam kompilasi vue3?

Persekitaran pengendalian tutorial ini: sistem windows7, versi vue3, komputer DELL G3.

Artikel ini menganalisis terutamanya pengoptimuman yang dilakukan dalam Vue3.0 peringkat kompilasi dan cara menggunakan strategi pengoptimuman ini untuk mengurangkan bilangan perbandingan dalam peringkat patch. Memandangkan keseluruhan vnode pokok komponen masih perlu dilalui apabila komponen dikemas kini, seperti templat berikut:

<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>
Salin selepas log masuk

Keseluruhan proses perbezaan adalah seperti yang ditunjukkan dalam rajah:

Apakah pengoptimuman yang telah dilakukan dalam kompilasi vue3?

Seperti yang anda lihat, kerana hanya terdapat satu nod dinamik dalam kod ini, terdapat banyak perbezaan dan traversal di sini yang sebenarnya tidak diperlukan Ini akan menyebabkan prestasi vnod untuk berkait secara langsung dengan saiz templat, dan dengan nod dinamik Nombor itu tiada kaitan dengan Apabila terdapat hanya beberapa nod dinamik dalam keseluruhan templat beberapa komponen, traversal ini membazirkan prestasi. Untuk contoh di atas, sebaiknya anda hanya perlu membezakan tag p bagi nod dinamik mesej terikat.

Vue.js 3.0 disusun untuk menjana Block tree dengan menganalisis templat statik semasa fasa penyusunan.

Block tree ialah blok bersarang yang memotong templat berdasarkan arahan nod dinamik Struktur nod di dalam setiap blok ditetapkan dan setiap blok hanya perlu dijejaki dengan satu Array Nod dinamik yang terkandung dalam. sendiri. Dengan bantuan Block tree, Vue.js meningkatkan prestasi kemas kini vnode daripada berkaitan dengan saiz keseluruhan templat kepada berkaitan dengan jumlah kandungan dinamik Ini adalah pencapaian prestasi yang sangat besar.

PatchFlag

Memandangkan algoritma diff tidak dapat mengelakkan operasi perbandingan yang tidak berguna antara DOM maya lama dan baharu, Vue.js 3.0 memperkenalkan patchFlag untuk menandakan kandungan dinamik . Semasa proses penyusunan, pengecam yang berbeza akan ditanda mengikut jenis atribut yang berbeza, sekali gus merealisasikan algoritma diff yang pantas. Semua jenis penghitungan untuk PatchFlags adalah seperti berikut:

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算法应该结束
}
Salin selepas log masuk

Pokok Sekat

Apakah pengoptimuman yang telah dilakukan dalam kompilasi vue3?

di sebelah kiri template Selepas penyusunan, fungsi render di sebelah kanan akan dihasilkan, yang mengandungi fungsi tambahan seperti _openBlock, _createElementBlock, _toDisplayString, _createElementVNode(createVnode), dsb.

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);
}
Salin selepas log masuk

Vnod yang dijana pada masa ini adalah seperti berikut:

Apakah pengoptimuman yang telah dilakukan dalam kompilasi vue3?

Nod maya yang dijana pada masa ini mempunyai satu lagi atribut dynamicChildren, yang mengumpul nod dinamik span.

Strategi pengoptimuman perbezaan nod:

Kami telah menganalisis sebelum itu apabila mengemas kini elemen nod dalam peringkat patch, fungsi patchElement akan dilaksanakan ia sekali lagi Pelaksanaannya:

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
  }
}
Salin selepas log masuk

Kami menganalisis proses ini dalam bab kemas kini komponen sebelumnya Semasa menganalisis kemas kini nod anak, kami tidak mengambil kira senario pengoptimuman pada masa itu, jadi kami hanya menganalisis. kemas kini perbandingan penuh.

Sebenarnya, jika ini vnode adalah Block vnode, maka kita tidak perlu melalui perbandingan penuh patchChildren, kita hanya perlu melalui patchBlockChildren untuk membandingkan dan mengemas kini dinamik dalam Block Hanya nod anak. Dapat dilihat bahawa prestasi telah dipertingkatkan dengan banyak, daripada perbandingan peringkat tree kepada perbandingan struktur linear.

Mari kita lihat pelaksanaannya:

const patchBlockChildren = (n1, n2) => {
  for (let i = 0; i < n2.dynamicChildren.length; i++) {
    patchElement(n1.dynamicChildren[i], n2.dynamicChildren[i])
  }
}
Salin selepas log masuk

Strategi pengoptimuman perbezaan atribut:

Seterusnya mari kita lihat pengoptimuman atribut Strategi perbandingan:

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, &#39;class&#39;, null, newProps.class, ...)
        }
      }
      // 存在动态 style 属性时
      if (patchFlag & PatchFlags.STYLE) {
        hostPatchProp(el, &#39;style&#39;, 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 === &#39;class&#39;) { // 更新 class 
    patchClass(el, nextValue)
  } else if (key === &#39;style&#39;) { // 更新 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(&#39;class&#39;); // 如果不需要class直接移除
  } else {
    el.className = nextValue
  }
}

function patchStyle(el, prevValue, nextValue = {}){
  ...
}

function patchAttr(el, key, nextValue){
  ...
}
Salin selepas log masuk

Ringkasan: vue3 akan menggunakan sepenuhnya patchFlag dan dynamicChildren untuk pengoptimuman. Jika ditentukan bahawa hanya terdapat perubahan setempat, seperti style perubahan, maka hanya hostPatchProp akan dipanggil dan parameter yang sepadan style akan dihantar untuk melakukan kemas kini tertentu ( kemas kini disasarkan ); jika terdapat dynamicChildren, patchBlockChildren akan dilaksanakan untuk perbandingan dan kemas kini, tidak akan melakukan perbandingan penuh dan kemas kini pada prop dan nod anak setiap kali. Rajah adalah seperti berikut:

Apakah pengoptimuman yang telah dilakukan dalam kompilasi vue3?

静态提升

静态提升是将静态的节点或者属性提升出去,假设有以下模板:

<div>
  <span>hello</span> 
  <span a=1 b=2>{{name}}</span>
  <a><span>{{age}}</span></a>
</div>
Salin selepas log masuk

编译生成的 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 */)
    ])
  ]))
}
Salin selepas log masuk

我们把模板编译成 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 */)
    ])
  ]))
}
Salin selepas log masuk

预解析字符串化

静态提升的节点都是静态的,我们可以将提升出来的节点字符串化。 当连续静态节点超过 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>
Salin selepas log masuk

开启静态提升 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))
}
Salin selepas log masuk

函数缓存

假如有如下模板:

<div @click="event => v = event.target.value"></div>
Salin selepas log masuk

编译后:

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))
}
Salin selepas log masuk

每次调用 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)
  }))
}
Salin selepas log masuk

总结

以上几点即为 Vuejs 在编译阶段做的优化,基于上面几点,Vuejspatch 过程中极大地提高了性能。

【相关推荐:vuejs视频教程web前端开发

Atas ialah kandungan terperinci Apakah pengoptimuman yang telah dilakukan dalam kompilasi vue3?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

PHP dan Vue: gandingan sempurna alat pembangunan bahagian hadapan PHP dan Vue: gandingan sempurna alat pembangunan bahagian hadapan Mar 16, 2024 pm 12:09 PM

PHP dan Vue: gandingan sempurna alat pembangunan bahagian hadapan Dalam era perkembangan pesat Internet hari ini, pembangunan bahagian hadapan telah menjadi semakin penting. Memandangkan pengguna mempunyai keperluan yang lebih tinggi dan lebih tinggi untuk pengalaman tapak web dan aplikasi, pembangun bahagian hadapan perlu menggunakan alat yang lebih cekap dan fleksibel untuk mencipta antara muka yang responsif dan interaktif. Sebagai dua teknologi penting dalam bidang pembangunan bahagian hadapan, PHP dan Vue.js boleh dianggap sebagai alat yang sempurna apabila digandingkan bersama. Artikel ini akan meneroka gabungan PHP dan Vue, serta contoh kod terperinci untuk membantu pembaca memahami dan menggunakan kedua-dua ini dengan lebih baik.

Soalan yang sering ditanya oleh penemuduga front-end Soalan yang sering ditanya oleh penemuduga front-end Mar 19, 2024 pm 02:24 PM

Dalam temu bual pembangunan bahagian hadapan, soalan lazim merangkumi pelbagai topik, termasuk asas HTML/CSS, asas JavaScript, rangka kerja dan perpustakaan, pengalaman projek, algoritma dan struktur data, pengoptimuman prestasi, permintaan merentas domain, kejuruteraan bahagian hadapan, corak reka bentuk, dan teknologi dan trend baharu. Soalan penemuduga direka bentuk untuk menilai kemahiran teknikal calon, pengalaman projek dan pemahaman tentang trend industri. Oleh itu, calon harus bersedia sepenuhnya dalam bidang ini untuk menunjukkan kebolehan dan kepakaran mereka.

Bagaimana untuk menggunakan bahasa Go untuk pembangunan bahagian hadapan? Bagaimana untuk menggunakan bahasa Go untuk pembangunan bahagian hadapan? Jun 10, 2023 pm 05:00 PM

Dengan perkembangan teknologi Internet, pembangunan front-end telah menjadi semakin penting. Terutamanya populariti peranti mudah alih memerlukan teknologi pembangunan bahagian hadapan yang cekap, stabil, selamat dan mudah diselenggara. Sebagai bahasa pengaturcaraan yang berkembang pesat, bahasa Go telah digunakan oleh semakin ramai pembangun. Jadi, adakah boleh menggunakan bahasa Go untuk pembangunan bahagian hadapan? Seterusnya, artikel ini akan menerangkan secara terperinci cara menggunakan bahasa Go untuk pembangunan bahagian hadapan. Mari kita lihat dahulu mengapa bahasa Go digunakan untuk pembangunan bahagian hadapan. Ramai orang berpendapat bahawa bahasa Go ialah a

Perkongsian pengalaman pembangunan C#: kemahiran pembangunan kolaboratif bahagian hadapan dan belakang Perkongsian pengalaman pembangunan C#: kemahiran pembangunan kolaboratif bahagian hadapan dan belakang Nov 23, 2023 am 10:13 AM

Sebagai pembangun C#, kerja pembangunan kami biasanya merangkumi pembangunan bahagian hadapan dan bahagian belakang Apabila teknologi berkembang dan kerumitan projek meningkat, pembangunan kolaboratif bahagian hadapan dan bahagian belakang menjadi semakin penting dan kompleks. Artikel ini akan berkongsi beberapa teknik pembangunan kolaboratif bahagian hadapan dan belakang untuk membantu pembangun C# menyelesaikan kerja pembangunan dengan lebih cekap. Selepas menentukan spesifikasi antara muka, pembangunan kolaboratif bahagian hadapan dan belakang tidak dapat dipisahkan daripada interaksi antara muka API. Untuk memastikan pembangunan kolaboratif bahagian hadapan dan belakang yang lancar, perkara yang paling penting ialah menentukan spesifikasi antara muka yang baik. Spesifikasi antara muka melibatkan nama antara muka

Adakah Django bahagian hadapan atau belakang? semaklah! Adakah Django bahagian hadapan atau belakang? semaklah! Jan 19, 2024 am 08:37 AM

Django ialah rangka kerja aplikasi web yang ditulis dalam Python yang menekankan pembangunan pesat dan kaedah bersih. Walaupun Django ialah rangka kerja web, untuk menjawab soalan sama ada Django ialah front-end atau back-end, anda perlu mempunyai pemahaman yang mendalam tentang konsep front-end dan back-end. Bahagian hadapan merujuk kepada antara muka yang pengguna berinteraksi secara langsung, dan bahagian belakang merujuk kepada program bahagian pelayan Mereka berinteraksi dengan data melalui protokol HTTP. Apabila bahagian hadapan dan bahagian belakang dipisahkan, program bahagian hadapan dan bahagian belakang boleh dibangunkan secara bebas untuk melaksanakan logik perniagaan dan kesan interaktif masing-masing, dan pertukaran data.

Meneroka teknologi bahagian hadapan bahasa Go: visi baharu untuk pembangunan bahagian hadapan Meneroka teknologi bahagian hadapan bahasa Go: visi baharu untuk pembangunan bahagian hadapan Mar 28, 2024 pm 01:06 PM

Sebagai bahasa pengaturcaraan yang pantas dan cekap, bahasa Go popular secara meluas dalam bidang pembangunan bahagian belakang. Walau bagaimanapun, beberapa orang mengaitkan bahasa Go dengan pembangunan bahagian hadapan. Malah, menggunakan bahasa Go untuk pembangunan bahagian hadapan bukan sahaja boleh meningkatkan kecekapan, tetapi juga membawa ufuk baharu kepada pembangun. Artikel ini akan meneroka kemungkinan menggunakan bahasa Go untuk pembangunan bahagian hadapan dan memberikan contoh kod khusus untuk membantu pembaca memahami dengan lebih baik bahagian ini. Dalam pembangunan front-end tradisional, JavaScript, HTML dan CSS sering digunakan untuk membina antara muka pengguna

Bolehkah golang digunakan sebagai front-end? Bolehkah golang digunakan sebagai front-end? Jun 06, 2023 am 09:19 AM

Golang boleh digunakan sebagai front-end Golang adalah bahasa pengaturcaraan yang sangat serba boleh yang boleh digunakan untuk membangunkan pelbagai jenis aplikasi, termasuk aplikasi front-end Dengan menggunakan Golang untuk menulis front-end, anda boleh menyingkirkan a siri masalah yang disebabkan oleh bahasa seperti JavaScript Contohnya, masalah seperti keselamatan jenis yang lemah, prestasi rendah dan sukar untuk mengekalkan kod.

Cara melaksanakan pemesejan segera pada bahagian hadapan Cara melaksanakan pemesejan segera pada bahagian hadapan Oct 09, 2023 pm 02:47 PM

Kaedah untuk melaksanakan pemesejan segera termasuk WebSocket, Tinjauan Panjang, Acara Dihantar Pelayan, WebRTC, dsb. Pengenalan terperinci: 1. WebSocket, yang boleh mewujudkan sambungan berterusan antara pelanggan dan pelayan untuk mencapai komunikasi dua hala masa nyata Bahagian hadapan boleh menggunakan API WebSocket untuk membuat sambungan WebSocket dan mencapai pemesejan segera dengan menghantar dan menerima. mesej; 2. Long Polling, teknologi yang menyerupai komunikasi masa nyata, dsb.

See all articles