Vue3.0中针对Virtual DOM优化

3,390 阅读2分钟

根据尤雨溪在VueConf2019上的演讲, 总结Vue3.0对于Virtual DOM的重构优化的思路。

Vue3.0设计目标

  • 更小
  • 更快
  • 加强TypeScript支持
  • 加强API设计一致性
  • 提高自身可维护性
  • 开放更多底层功能

如何更快?

  • Object.defineProperty -> Proxy

  • Virtual Dom 重构

  • 更多编译优化:

    • slot默认编译为函数
    • Momomorphic vnode factory
    • Compiler-generated flags for vnode/children types

Virtual Dom 重构

传统Virtual DOM的性能瓶颈

数据变更之后,新的Virtual DOM和旧的Virtual DOM进行 patch 算法比较,并算出二者之间的差异,将差异进行修改。但是传统Virtual DOM,进行算法比对时颗粒度是组件,每个组件作为一个颗粒。

虽然Vue能够保证触发更新的组件最小化,但是单个组件内部依然需要遍历该组件的整个Virtual DOM树。

传统Virtual DOM的性能跟模板大小正相关,跟动态节点的数量无关。模板或者组件有多大,那么在进行数据更新时损耗的性能就有多大,但实际上,这种方式利用率很低。如上图所示,在上述template中,发生改变的地方只有message插值的部分,整体结构不变,但是数据更新的时候,比对整个template结构,这样就存在性能损耗。

所以在一些组件整个模板内只有少量动态节点的情况下,传统方法遍历存在性能的浪费。

Vue3.0 Virtual DOM

动静结合:找到动态变化的部分,更新时只对比可以变化的部分,减少性能损耗。

三种类型

节点结构不变

最简单的情况:

  • 节点结构完全不会改变
  • 只有一个动态节点

这个时候没有必要比较结构顺序。

节点结构变化 v-if

  • v-if 外部:只有v-if是动态节点
  • v-if 内部:只有 {{ message }} 是动态节点

把模板切分成两个部分,各部分相对静态。

节点结构变化 v-for

  • v-for 外部:只有v-for是动态节点 (fragment)
  • 每个v-for循环内部:只有 {{ item.message }} 是动态节点

区块树Block tree

以结构性指令为边界,将整个模板切割成一个一个的相对内部静态的块。

  • 将模板基于动态节点指令切割为嵌套的区块。
  • 每个区块内部的节点结构是固定的。
  • 每个区块只需要以一个Array追踪自身包含的动态节点。

升级后

新策略将Virtual DOM更新性能能由与模板整体大小相关提升为与动态内容的数量相关。


欢迎关注我的公众号,谢谢大家!