响应式
vue2中采用 defineProperty来劫持整个对象,然后进行深度遍历所有属性,给每个属性添加getter和setter,实现响应式;
vue3采用proxy重写了响应式系统,因为proxy可以对整个对象进行监听,所以不需要深度遍历
- 可以监听动态属性的添加
- 可以监听到数组的索引和数组
length属性 - 可以监听删除属性
defineProperty
- 检测不到对象属性的添加和删除
- 数组
API方法无法监听到 - 需要对每个属性进行遍历监听,如果嵌套对象,需要深层监听,造成性能问题
源码体积
相比Vue2,Vue3整体体积变小了,除了移出一些不常用的API,最重要的是Tree shanking
任何一个函数,如ref、reavtived、computed等,仅仅在用到的时候才打包,没用到的模块都被摇掉,打包的整体体积变小
Tree shaking
Tree shaking是基于ES6模板语法(import与exports),主要是借助ES6模块的静态编译思想,在编译时就能确定模块的依赖关系,以及输入和输出的变量
Tree shaking无非就是做了两件事:
- 编译阶段利用
ES6 Module判断哪些模块已经加载 - 判断那些模块和变量未被使用或者引用,进而删除对应代码
通过Tree shaking,Vue3给我们带来的好处是:
- 减少程序体积(更小)
- 减少程序执行时间(更快)
- 便于将来对程序架构进行优化(更友好)
编译阶段
回顾Vue2,我们知道每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把用到的数据property记录为依赖,当依赖发生改变,触发setter,则会通知watcher,从而使关联的组件重新渲染。
Vue3在编译阶段,做了进一步优化。主要有如下:
diff算法优化- 静态提升
- 事件监听缓存
SSR优化
diff算法优化
一个组件结构如下:
1 | <template> |
可以看到,组件内部只有一个动态节点,剩余一堆都是静态节点,所以这里很多 diff 和遍历其实都是不需要的,造成性能浪费。
vue3在diff算法中相比vue2增加了静态标记。
关于这个静态标记,其作用是为了会发生变化的地方添加一个flag标记,下次发生变化的时候直接找该地方进行比较。
静态类型枚举如下
1 | export const enum PatchFlags { |
静态提升
Vue3中对不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用。
这样就免去了重复的创建节点,大型应用会受益于这个改动,免去了重复的创建操作,优化了运行时候的内存占用。
事件监听缓存
默认情况下绑定事件行为会被视为动态绑定,所以每次都会去追踪它的变化。
开启事件侦听器缓存后没有了静态标记,也就是说下次diff算法的时候直接使用。
SSR优化
当静态内容大到一定量级时候,会用createStaticVNode方法在客户端去生成一个static node,这些静态node,会被直接innerHtml,就不需要创建对象,然后根据对象渲染。
- 本文标题:vue3性能提升
- 本文作者:灵感胜于汗水
- 创建时间:2022-10-20 14:16:12
- 本文链接:https://cjhsyc.github.io/2022/10/20/vue3性能提升/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!