根据官方介绍

客户端渲染效率比Vue2提升了2-3倍。 SSR渲染效率比Vue2提升了2-3倍。

那么具体来讲,Vue3在那些方面改进导致了效率的提升?

静态提升

  • 静态节点会被提升
    • 元素节点
    • 没有绑定动态内容

Vue2中,会将模块template预编译为一个render函数。

  1. // Vue2 的静态节点
  2. render() {
  3. createVNode('h1', null, 'content')
  4. }
  5. // Vue3的静态节点
  6. const hoisted = createVNode('h1', null, 'content')
  7. render() {
  8. // 使用hoisted即可
  9. }

对于静态节点(没有动态绑定任何值,一个单纯的元素标签),Vue2中每调用一次render函数都会去编译静态节点。但在Vue3中,既然静态节点是不会做改变的,那么直接将静态节点提出render函数外,这样该静态节点只编译一次。

  • 静态属性会被提升
    1. <div class="info"></div>
    1. const hoisted = { class: 'info' }
    2. render(cache) {
    3. createVNode('div', hoisted, '')
    4. }

    预字符串化

    当编译时遇到大量连续静态内容,会直接编译为一个普通字符串节点。
    1. <ul class="info">
    2. <li>li</li>
    3. <li>li</li>
    4. <li>li</li>
    5. <li>li</li>
    6. </ul>
    经过字符串化后就是字符串化后的元素。

    缓存事件处理函数

    1. <button @click="count++">add</button>
    1. // vue2
    2. render(ctx) {
    3. return createVNode("button", {
    4. onClick: function($event) {
    5. ctx.count++
    6. }
    7. })
    8. }
    9. // vue3
    10. render(ctx, _cache) {
    11. return createVNode("button", {
    12. onClick: _cache[0] || (_cache[0] = $event => ctx.count++)
    13. }
    Vue2对事件的处理是动态生成的,而在Vue3中是放在_cache缓存中,该参数是一个数组,如果数组中没有该元素(即事件),则将该元素赋值一个事件;否则就直接使用缓存中的事件。

这样处理保证了事件处理函数只生成一次。

Block Tree

在Vue2中对比新旧两颗树时,不知道那些是静态/动态的。只能一层层比较,浪费了很长的事件用于“无意义”的比较。

而在Vue3中运用Block Tree,它会标记动态节点(PatchFlag),在对比树时会过滤静态节点,将动态节点直接放在根节点,这样就节省了很大的对比时间。

PatchFlag

Vue2在节点之间对比的时候,并不知道节点中那些属性/信息会变化,所以会全部比较。

在Vue3中引入了PatchFlag,针对不同的Flag类型,Vue3会自动只比较相应的属性。

  1. var PatchFlagNames = {
  2. [1]: `TEXT`,
  3. [2]: `CLASS`,
  4. [4]: `STYLE`,
  5. [8]: `PROPS`,
  6. [16]: `FULL_PROPS`,
  7. [32]: `HYDRATE_EVENTS`,
  8. [64]: `STABLE_FRAGMENT`,
  9. [128]: `KEYED_FRAGMENT`,
  10. [256]: `UNKEYED_FRAGMENT`,
  11. [512]: `NEED_PATCH`,
  12. [1024]: `DYNAMIC_SLOTS`,
  13. [2048]: `DEV_ROOT_FRAGMENT`,
  14. [-1]: `HOISTED`,
  15. [-2]: `BAIL`
  16. };

下述代码就是Vue3中PatchFlag在代码中的表现。1-代表了TEXT类型是一个会变化的属性。

  1. _createVNode("h1", null, _toDisplayString($props.msg), 1 /* TEXT */),