Vue3 源码解读系列(一)——Vue3的优化

Vue3 对比 Vue2 的优化

源码优化

  • 使用 monorepo 管理代码

    将各模块拆分到不同的 package 中,每个 package 有各自的 API、类型定义和测试,使得模块拆分更加细化,模块之间的依赖也更加明确。

  • 使用 TypeScript 开发代码

    相比 Vue2 使用 flow 的优势:

    1. 提供了更好的类型推导
    2. 对 TypeScript 更加友好

性能优化

  • 减少体积

    • 移除一些冷门的 feature
    • 引入 tree-shaking 技术
  • 数据劫持优化

    Vue2 采用 Object.defineProperty() 劫持数据的 getter 和 setter,即在对象上添加 get 和 set 方法。

    缺点:

    1. 无法知道用户具体要访问哪一个属性,如果要实现深度监听需要递归给每一个对象都添加 get 和 set 方法,这会带来相当大的性能负担
    2. 无法检测对象属性的新增和删除

    Vue3 采用了 Proxy 劫持数据的 getter 和 setter。(Proxy 并不能监听到内部深层次的对象变化,因此 Vue3 的处理方式是在 getter 中去递归响应式,起到懒深度监听的效果)

    优点:

    1. 可以实现懒深度响应式,对性能有大幅度优化
  • 编译优化

    Vue2

    • 静态标记:创建一个数组用于缓存静态节点,并且生成的 vnode 带有 inStatic: true 属性,用于在 diff 中跳过它们的对比

    Vue3

    • 静态提升:将静态节点提取到 render 函数外面,减少 vnode的创建带来的性能损耗
    • 预字符串化:将大量连续的静态节点转换为字符串,既减少 vnode 创建过程,也可以减少代码体积
    • 缓存事件处理函数:每次 render 函数执行过后,生成新的 vnode,对 vnode 的 props 中事件属性进行 patch 的时候,就直接取上一次缓存的函数,如果没有缓存,每次函数都是新的,引用不一致,会造成组件的更新
    • Block tree:在模板编译过程中收集动态子节点,能够在 diff 过程中根据动态子节点数量更新
    • PatchFlag:比较动态子节点时配合使用 patchFlag 比较动态属性
  • 优化

    在 Vue2 中,无论插槽内容是否改变,都会重新生成 vnode 节点。

    在 Vue3 中,会将插槽分为静态插槽和动态插槽,组件更新时只会比较动态插槽。

语法优化

  • 优化逻辑组织

    Vue2 中使用的 Options API 是按照 methods、data 等进行分类。

    缺点:

    1. 当组件变得越来越大时,一个组件可能有多个逻辑关注点,此时 Options API 就会造成很差的开发体验

    Vue3 中提供了 Composition API。

    优点:

    1. 可以将相关逻辑放在一块,无需在一个文件的多个地方 “反复横跳”
    2. Composition API 无需使用 this,因此对 tree-shaking 也更加友好
  • 优化逻辑复用

    Vue2 中使用 mixin 来保存共用的逻辑。

    缺点:

    1. 每个 mixin 之间是无感的,这会导致多个 mixin 容易定义相同的变量,导致命名冲突
    2. 对于组件而言,如果在模板中使用不在当前组件中定义的变量,会导致数据来源不清晰的问题

    Vue3 中通过自定义 hook 来保存共用的逻辑。

    优点:

    1. 可以在引入的时候对同名变量重命名,以解决命名冲突的问题
    2. 可以通过查看具体使用了哪一个 hook 来追溯数据来源
    3. 可以向自定义 hook 传递参数来改变逻辑,而 mixin 不行

你可能感兴趣的:(Vue,vue.js,前端,javascript)