根据尤雨溪在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更新性能能由与模板整体大小相关提升为与动态内容的数量相关。
欢迎关注我的公众号,谢谢大家!