1、Vue 3.0 性能提升主要是通过哪几方面体现的?
-
响应式系统升级
- 使用 Proxy 对象重写响应式系统:vue2.x 中 使用 defineProperty 在初始化时遍历 data 中的成员,实现响应式,若成员中嵌套成员则递归实现 get 、set ,如果 data 中的成员未被使用,也会做响应式处理的操作。但在 Vue3 中,只有在成员被用到的时候才会处理响应式
- 可以监听动态新增的属性
- 可以监听删除的属性
- 可以监听数组的索引和 length 属性
-
编译优化
-
Vue2.x 中通过标记静态根节点,优化 diff 的过程
-
Vue3.0 中标记和提升所有的静态根节点,diff 的时候只需要对比动态节点内容
-
- Fragments:无需唯一根节点
- 静态提升:所有静态节点提升只在初始化时渲染,优化 diff
- Patch flag:标记所有动态节点,优化 diff ,检查标记的内容即可
- 缓存事件处理函数:将事件缓存到 cache 对象中,需要用时直接取出,避免不必要的更新操作
-
-
源码体积的优化
- 移除不常用的API 例如:inline-template、filter 等
- 优化 Tree-shaking :按需打包,无引入不打包
2、Vue 3.0 所采用的 Composition Api 与 Vue 2.x使用的Options Api 有什么区别?
- Options Api
- 包含一个描述组件的选项(data、methods、props等)的对象
- Options API 开发复杂组件,同一个功能逻辑的代码被拆分到不同选项
- Composition Api
- 一组基于函数的 API
- 可以更灵活的组织组件的逻辑
- 总结:Vue 3.0 中的 Composition Api 我们可以将同一功能的代码写在同一函数内部使用,返回页面所用到的内容,当我们查看功能逻辑代码时,只需要查看该功能函数即可,并且其他组件也可复用该功能函数,它使代码功能整齐且可提取可重用,并且在 Composition Api 中同样可以使用 Option API。而 Option Api 中的代码只能在该组件中使用,代码被划分到不同选项中,难以提取。
3、Proxy 相对于 Object.defineProperty 有哪些优点?
-
defineProperty
- 无法监听新增的属性,需要使用 $set 新增
- 无法监听删除的属性
- 无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应
- 只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。Vue 2.x里,是通过 递归 + 遍历 data 对象来实现对数据的监控的,如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象是才是更好的选择
-
Proxy
- 可以监听动态新增的属性:Proxy 监听的是整个对象,因此新增的时候同样会触发 set 方法触发更新
- 可以监听删除的属性:内部使用 deleteProperty ,监听属性删除并触发更新
- 可以监听数组的索引和 length 属性
- 可以监听整个对象,并不会在初始化时深度遍历对象进行响应式处理,只会在用到该对象时,实现响应式,访问到该对象属性时才会实现属性的响应式处理
4、Vue 3.0 在编译方面有哪些优化?
- 针对静态节点的优化:
- Virtual DOM机制调整
- 内存优化,更少的占用
- 按需加载,更灵活的组件化
- Fragments: 新引入Fragments(片段)特性,Vue 3.x 模板中不需要再创建一个唯一的根节点,模板里可以直接放文本内容或者很多同级的标签, Vue2.x 需要唯一的节点
- 静态提升:静态节点都会被提升到 render 的外部,只有初始化时会被创建,再次调用 render 时不会再次创建,可以直接重用这些静态节点对应的 vnode ,静态Node,静态绑定的class、id不再作更新处理
- Patch flag:标记所有动态节点,优化 diff ,检查标记的内容即可
- 缓存事件处理函数:将事件缓存到 cache 对象中,需要用时直接取出,避免不必要的更新操作。编辑器会为你动态创建一个内联函数,内联函数里面再去引用当前组件上最新的handler。之后编辑器会将内联函数缓存。每次重新渲染时如果事件处理器没有变,就会使用缓存中的事件处理而不会重新获取事件处理器。这个节点就可以被看作是一个静态的节点。这种优化更大的作用在于当其作用域组件时,之前每次重新渲染都会导致组件的重新渲染,在通过handler缓存之后,不会导致组件的重新渲染了。
5、Vue.js 3.0 响应式系统的实现原理?
reactive:创建响应式对象,将一个普通对象或者 代理对象设置为 Proxy 对象,使用 Proxy 监听整个对象,获取属性时使用 get 方法中 track 方法收集依赖,设置属性时使用 set 方法中 trigger 方法触发更新,删除属性时使用 deleteProperty 触发更新,通过 reactive 方法返回的则是响应式对象
computed:创建 ref 对象,将响应式对象属性存入并返回,内部使用的是 effect 函数,接收一个函数作为参数,在 effect 中调用该函数,并收集依赖,将函数存储
ref:基本数据类型的响应式,利用 reactive 处理为响应式对象,存储在 value 属性中
toRefs: 将代理对象内部的属性也变成响应式数据,将引用数据类型,遍历到目标对象上,可实现解构方法,因 reactive 无法实现解构,reactive 返回的对象可通过此方法进行解决,解构出的对象仍然是响应式数据