Vue.js 3.0 对比 Vue 2
1、Vue 3.0 性能提升主要是通过哪几方面体现的?
一.编译阶段
-
diff 算法优化
vue3 在 diff 算法中相比 vue2 增加了静态标记
关于这个静态标记,其作用是为了会发生变化的地方添加一个 flag 标记,下次发生变化的时候直接找该地方进行比较 -
静态提升
Vue3 中对不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用
这样就免去了重复的创建节点,大型应用会受益于这个改动,免去了重复的创建操作,优化了运行时候的内存占用 -
事件监听缓存
默认情况下绑定事件行为会被视为动态绑定,所以每次都会去追踪它的变化 -
SSR 优化
当静态内容大到一定量级时候,会用 createStaticVNode 方法在客户端去生成一个 static node,这些静态 node,会被直接 innerHtml,就不需要创建对象,然后根据对象渲染
二.源码体积
相比 Vue2,Vue3 整体体积变小了,除了移出一些不常用的 API,再重要的是 Tree shanking
任何一个函数,如 ref、reavtived、computed 等,仅仅在用到的时候才打包,没用到的模块都被摇掉,打包的整体体积变小
三、响应式系统
vue2 中采用 defineProperty 来劫持整个对象,然后进行深度遍历所有属性,给每个属性添加 getter 和 setter,实现响应式
vue3 采用 proxy 重写了响应式系统,因为 proxy 可以对整个对象进行监听,所以不需要深度遍历
可以监听动态属性的添加
可以监听到数组的索引和数组 length 属性
可以监听删除属性
2、Vue 3.0 所采用的 Composition Api 与 Vue 2.x 使用的 Options Api 有什么区别?
- 在逻辑组织和逻辑复用方面,Composition API 是优于 Options API
- Composition API 几乎是函数,会有更好的类型推断。
- Composition API 对 tree-shaking 友好,代码也更容易压缩
- Composition API 中见不到 this 的使用,减少了 this 指向不明的情况
- 如果是小型组件,可以继续使用 Options API,也是十分友好的
3、Proxy 相对于 Object.defineProperty 有哪些优点?
- Proxy 可以直接监听对象而非属性;
- Proxy 可以直接监听数组的变化;
- Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;
- Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;
4、Vue 3.0 在编译方面有哪些优化?
-
diff 算法优化
vue3 在 diff 算法中相比 vue2 增加了静态标记
关于这个静态标记,其作用是为了会发生变化的地方添加一个 flag 标记,下次发生变化的时候直接找该地方进行比较 -
静态提升
Vue3 中对不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用
这样就免去了重复的创建节点,大型应用会受益于这个改动,免去了重复的创建操作,优化了运行时候的内存占用 -
事件监听缓存
默认情况下绑定事件行为会被视为动态绑定,所以每次都会去追踪它的变化 -
SSR 优化
当静态内容大到一定量级时候,会用 createStaticVNode 方法在客户端去生成一个 static node,这些静态 node,会被直接 innerHtml,就不需要创建对象,然后根据对象渲染
5、Vue.js 3.0 响应式系统的实现原理?
Vue3 使用 Proxy 对象重写响应式系统,这个系统主要有以下几个函数来组合完成的:
1、reactive:
接收一个参数,判断这参数是否是对象。不是对象则直接返回这个参数,不做响应式处理
创建拦截器对象 handler, 设置 get/set/deleteProperty
get
收集依赖(track)
返回当前 key 的值。
如果当前 key 的值是对象,则为当前 key 的对象创建拦截器 handler, 设置 get/set/deleteProperty
如果当前的 key 的值不是对象,则返回当前 key 的值
set
设置的新值和老值不相等时,更新为新值,并触发更新(trigger)
deleteProperty
当前对象有这个 key 的时候,删除这个 key 并触发更新(trigger)
返回 Proxy 对象
2、effect: 接收一个函数作为参数。作用是:访问响应式对象属性时去收集依赖
3、track:
接收两个参数:target 和 key
如果没有 activeEffect,则说明没有创建 effect 依赖
如果有 activeEffect,则去判断 WeakMap 集合中是否有 target 属性,
WeakMap 集合中没有 target 属性,则 set(target, (depsMap = new Map()))
WeakMap 集合中有 target 属性,则判断 target 属性的 map 值的 depsMap 中是否有 key 属性
depsMap 中没有 key 属性,则 set(key, (dep = new Set()))
depsMap 中有 key 属性,则添加这个 activeEffect
4、trigger:
判断 WeakMap 中是否有 target 属性
WeakMap 中没有 target 属性,则没有 target 相应的依赖
WeakMap 中有 target 属性,则判断 target 属性的 map 值中是否有 key 属性,有的话循环触发收集的 effect()