一文看懂 Vue.js 3.0 的优化

Vue.js 从 1.x 到 2.0 版本,最大的升级就是引入了虚拟 DOM 的概念,它为后续做服务端渲染以及跨端框架 Weex 提供了基础。

Vue.js 2.x 发展了很久,现在周边的生态设施都已经非常完善了,而且对于 Vue.js 用户而言,它几乎满足了我们日常开发的所有需求。在迭代 2.x 版本的过程中,小右发现了很多需要解决的痛点,比如源码自身的维护性,数据量大后带来的渲染和更新的性能问题,一些想舍弃但为了兼容一直保留的鸡肋 API 等;另外,小右还希望能给开发人员带来更好的编程体验,比如更好的 TypeScript 支持、更好的逻辑复用实践等,所以他希望能从源码、性能和语法 API 三个大的方面优化框架。

那么接下来,我们就一起来看一下 Vue.js 3.0 具体做了哪些优化, 了解Vue.js 3.0的升级给我们开发带来什么收益。

一、源码优化

1

更好的代码管理方式:monorepo

>>>>

Vue.js 2.x

源码托管在 src 目录

src
├── compiler        # 编译相关
├── core            # 核心代码
├── platforms       # 不同平台的支持
├── server          # 服务端渲染
├── sfc             # .vue 文件解析
├── shared          # 共享代码

>>>>

Vue.js 3.0

monorepo 把这些模块拆分到不同的目录中,每个模块有各自的API类型定义和测试。这样使得模块拆分更细化,职责划分更明确,模块之间的依赖关系也更加明确,开发人员也更容易阅读、理解和更改所有模块源码,提高代码的可维护性。

@vue
├── compiler-core
│   ├── LICENSE
│   ├── README.md
│   ├── dist
│   │   ├── compiler-core.cjs.js
│   │   ├── compiler-core.cjs.prod.js
│   │   ├── compiler-core.d.ts
│   │   └── compiler-core.esm-bundler.js
│   ├── index.js
│   └── package.json
├── compiler-dom
│   …
├── reactivity
│   …
├── runtime-core
│   …
├── runtime-dom
│   …
└── shared
   …

2

有类型的 JavaScript:TypeScript

>>>>

Vue.js 2.x

使用Flow做类型检查,Flow 是 Facebook 出品的 JavaScript 静态类型检查工具,它可以以非常小的成本对已有的 JavaScript 代码迁入,非常灵活。但是Flow 对于一些复杂场景类型的检查,支持得并不好。

>>>>

Vue.js 3.0

使用 TypeScript 重构了整个项目。TypeScript提供了更好的类型检查,能支持复杂的类型推导。

二、性能优化

1

源码体积优化

>>>>

Vue.js 3.0

移除一些冷门的 feature(比如 filter、inline-template 等);

引入 tree-shaking 的技术,减少打包体积;

2

数据劫持优化

>>>>

Vue.js 2.x

Vue.js 2.x是采用数据劫持结合发布者-订阅者模式的方式来达到数据响应效果的。大体思路参考下图。(详细原理自行学习,哈哈)

8a422db19d52d7471ba0ae123114680d.png

Vue.js 2.x 内部是通过 Object.defineProperty 这个 API 去劫持数据的 getter 和 setter,具体是这样的:

Object.defineProperty(data, 'a',{
  get(){
    // track
  },
  set(){
    // trigger
  }
})

但这个 API 有一些缺陷:

它必须预先知道要拦截的 key 是什么,所以它并不能检测对象属性的添加和删除。尽管 Vue.js 为了解决这个问题提供了 $set 和 $delete 实例方法;

对于嵌套层级较深的对象,如果要劫持它内部深层次的对象变化,就需要递归遍历这个对象,执行 Object.defineProperty 把每一层对象数据都变成响应式的。如果我们定义的响应式数据过于复杂,这就会有相当大的性能损耗;

>>>>

Vue.js 3.0

为了解决上述 2 个问题,Vue.js 3.0 使用了 Proxy API 做数据劫持,它的内部是这样的:

observed = new Proxy(data, {
  get() {
    // track
  },
  set() {
    // trigger
  }
})

使用了 Proxy API 做数据劫持,它劫持的是整个对象,对于对象的属性的增加和删除都能检测到。

Proxy API 并不能监听到内部深层次的对象变化,因此 Vue.js 3.0 的处理方式是在 getter 中去递归响应式,这样的好处是真正访问到的内部对象才会变成响应式,而不是无脑递归,这样无疑也在很大程度上提升了性能,我会在后面分析响应式章节详细介绍它的具体实现原理 。

3

编译优化

>>>>

Vue.js 2.x

通过数据劫持和依赖收集,Vue.js 2.x 的数据更新并触发重新渲染的粒度是组件级的,虽然 Vue 能保证触发更新的组件最小化,但在单个组件内部依然需要遍历该组件的整个 vnode 树。这就会导致 vnode 的性能跟模版大小正相关,跟动态节点的数量无关,当一些组件的整个模版内只有少量动态节点时,这些遍历都是性能的浪费。

>>>>

Vue.js 3.0

通过编译阶段对静态模板的分析,编译生成了 Block tree。Block tree 是一个将模版基于动态节点指令切割的嵌套区块,每个区块内部的节点结构是固定的,而且每个区块只需要以一个 Array 来追踪自身包含的动态节点。借助 Block tree,Vue.js 将 vnode 更新性能由与模版整体大小相关提升为与动态内容的数量相关。

三、语法 API 优化

1

逻辑组织优化

>>>>

Vue.js 2.x

在 Vue.js 2.x 版本中,编写组件本质就是在编写一个“包含了描述组件选项的对象”,我们把它称为 Options API。Options API 的设计是按照 methods、computed、data、props 这些不同的选项进行分类。和一个逻辑点相关的代码可能写在多个Option里,非常分散,如果需要修改一个逻辑点,就需要在单个文件中不断切换和寻找。

>>>>

Vue.js 3.0

Vue.js 3.0 提供了一种新的 API:Composition API,它有一个很好的机制去解决这样的问题,就是将某个逻辑关注点相关的代码全都放在一个函数里,这样当需要修改一个功能时,就不再需要在文件中跳来跳去。

2

逻辑复用优化

>>>>

Vue.js 2.x

我们通常会用 mixins 去复用逻辑。使用单个 mixin 似乎问题不大,但是当我们一个组件混入大量不同的 mixins 的时候,会存在两个非常明显的问题:命名冲突和数据来源不清晰。

每个 mixin 都可以定义自己的 props、data,它们之间是无感的,所以很容易定义相同的变量,导致命名冲突;

对组件而言,如果模板中使用不在当前组件中定义的变量,那么就会不太容易知道这些变量在哪里定义的,这就是数据来源不清晰;

>>>>

Vue.js 3.0

使用 hook 函数,整个数据来源清晰了,也不会出现命名冲突的问题。

3

更好的类型支持

因为它们都是一些函数,在调用函数时,自然所有的类型就被推导出来了。不像 Options API 所有的东西使用 this。

4

tree-shaking 友好

tree-shaking有一个两个要求(对tree-shaking不熟的,还是自行去学习,哈哈):

必须是import导入。

是必须是单个函数或常量导出

>>>>

Vue.js 2.x

直接导出的是整个vue实例,如果我们只是简单的用某一些功能的话就有点累赘。

>>>>

Vue.js 3.0

用到的函数可以通过import声明,对“按需加载”有更好的支持。

注意

Composition API 属于 API 的增强,它并不是 Vue.js 3.0 组件开发的范式,如果组件足够简单,可以使用 Options API。

3123bcb3a440d53d852a2d803fc05fec.png

本文主要总结了 Vue.js 3.0 升级做了几个方面的优化,以及为什么会需要这些优化。希望学习完后我们也可以像小右一样去审视自己的工作,有哪些痛点,找到可以改进和努力的方向并实施,只有这样才能够不断提升自己的能力,工作上也会有不错的产出。

资料参考来源:

黄轶老师--《Vue.js 3.0 核心源码解析》课程

感谢阅读~~

373e6f274be79481a78a12c42c0baf43.jpeg

扫码关注我们

前端麻辣烫

3db2629fd8e173be5aa644b5f42eb1dd.gif

仙女都在看

点点点,赞和在看都在这儿!

addebd56a4a130821721334a16d4052e.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值