vue3的性能提升
1. diff 算法的优化
增加了静态标记, 被标记为-1的节点不会参与diff比较。
因为为vue3可以实现精准定位到动态节点,即那些可能需要重新渲染的节点。
曾经diff需要一层层比较整个新旧虚拟dom树找到哪些值改变。
- 现在vue3在编译时,利用静态标记patchFlag 标记节点的动态属性。
例如class、style、props,含有动态属性的节点就是动态节点。
每个组件的顶层vnode会有一个
dynamicChildren
属性,以数组形式存放该节点下所有动态节点。在运行render后,会遍历这个数组进行靶向更新。也就是说只需要比较动态节点的新旧变化了
2. 静态提升
对于静态节点,把创建dom节点的放在render函数之外。这样就只用创建一次,多次复用。
1 | export function render(_ctx, _cache, $props, $setup, $data, $options) { |
提升后
1 | const _hoisted_1 = /*#__PURE__*/_createVNode("span", null, "你好", -1 /* HOISTED */) |
3. 事件监听缓存
用一个cache缓存事件处理函数
1 | export function render(_ctx, _cache, $props, $setup, $data, $options) { |
4. Tree shaking
tree shaking 是一种清除多于代码的优化打包体积的技术。
- vue2中所有功能代码都被打包,因为vue2是单例模式,所有方法都在vue构造函数生成的单例上,treeshaking无法区分某个属性、方法是否用到。
- vue3利用ES6 module。 静态编译时就可以把未使用的功能排除
5. 响应式系统
- vue2 使用
defineProperty
来劫持对象,深度遍历所有属性给每个属性添加getter setter
- vue3 使用
Proxy
代理对象。defineProperty
只能劫持对象属性,所以需要遍历所有属性。而Proxy
是直接代理对象。- vue2由于
defineProperty
而不能监听数组,所以要重写数组方法。 - 当一个对象的属性还是一个对象时,
Proxy
采用懒递归,在getter发现读到的属性时对象时才会创建该对象的代理并返回。