发展历程
1.0 到 2.0,最大的优化就是引入虚拟DOM的概念
2.0 的痛点:
- 源码自身的维护性:数据量大后带来的渲染和更新的性能问题
- 兼容性:想舍弃但为了兼容一直保留的鸡肋API
一共三点:源码、性能、自身API
源码优化
- 目的是让代码更易于开发和维护
- 使用
monorepo和ts管理和开发源码,提升自身代码可维护性 - 相对于 2.0 的源码组织方式,
monorepo把这些模块拆分到不同的package中,每个package有各自的API、类型定义和测试
monorepo
- 模块拆分更细化,职责划分更明确,模块之间的依赖关系更加明确,开发人员也更容易阅读、理解和更改所有模块源码,提高代码的可维护性
package(比如reactivity响应式库)是可以独立于Vue.js使用,如果用户只想使用Vue.js 3.0的响应式能力,可单独依赖这个响应式库而不是去依赖整个Vue.js,减小了引用的体积大小。
有类型的JavaScript:TypeScript
2.0 使用
flow进行类型校验,但是flow对一些复杂场景类型的检查,支持的并不好,比如:const propOptions: any = vm.$options.props // wtf flow?3.0 使用
ts的原因:- 首先
ts能支持复杂的类型推导 - 由于源码使用
ts编写,省去了单独维护d.ts文件的麻烦 ts保持着一定频率的迭代和更新
性能优化
3.0在源码体积减少方面做的工作:
- 移除一些冷门的
feature - 引入
tree-shaking的技术
tree-shaking:依赖ES2015模块语法的静态结构(即import和export),通过编译阶段的静态分析,找到没有引入的模块并打上标记。
如果项目中没有引入
Transition、keepAlive等组件,那么他们对应的代码就不会打包。这样也就间接的达到了减少包体积的目的。
数据劫持优化
实现
DOM功能,就必须劫持数据的访问与更新- 通过数据的访问,建立数据和
DOM的依赖关系 - 实现
DOM自动更新,就必须劫持数据的更新,也就是说当数据发生改变后能自动执行一段代码去更新DOM。
1.0 和 2.0都是通过Object.defineProperty 劫持数据的getter 和 setter
3.0 使用了
Proxy API做数据劫持,由于劫持的是整个对象,所以对对象的属性的增加和删除都能监听到。缺点是:不能监听到内部深层次的对象变化,3.0的处理方式是在getter中递归响应式,好处是真正访问到内部对象才会变成响应式,而不是无脑递归,同时也提升了性能。编译优化
new Vue --- init --- $mount --- compile --- render ---vnode --- patch --- DOM响应式优化,除了在数据劫持时优化,还可以在patch阶段,通过在编辑阶段优化编译的结果,实现运行时patch过程的优化。
3.0 通过编译阶段对静态模板的分析,编译生成了
Block tree。Block tree
Block tree是一个将模板基于动态节点指令切割的嵌套区块,每个区块内部的节点结构是固定的,每个区块只需要以一个Array来追踪自身包含的动态节点- 借助
Block tree,Vue.js将vnode更新性能由与模板整体大小相关提升为与动态内容的数量相关
3.0在编译阶段还包含对
slot的编译优化、事件侦听函数的缓存优化,并且在运行时重写了diff算法语法 API 优化:Composition API
优化逻辑组织
1.0 和 2.0 时,编写组件本质就是在编写一个 “包含了描述组件选项的对象”,称为
Options API,写法符合正常逻辑思维,易于理解。Options API
Options API的设计是按照methods、computed、data、props这些不同的选项分类- 当组件小的时候,这种分类一目了然;但是在大型组件中,一个组件可能有多个逻辑关注点
- 当使用
Options API的时候,每一个关注点都有自己的Options - 如果需要修改一个逻辑关注点,就需要在单个文件中不断上下切换和寻找
Composition API
- 将某个逻辑关注点相关的代码全都放在一个函数里
- 这样当需要修改一个功能时,就不再需要在文件中跳来跳去
优化逻辑复用
2.0的
mixin 存在的问题:- 首先每个mixin都可以定义自己的
props、data。它们之间是无感的,所以很容易定义相同的变量,导致命名冲突。 - 对组件而言,如果模板中使用不在当前组件中定义的变量,那么就不太容易知道这些变量定义在哪里,导致数据来源不清晰。
3.0 的
Composition API解决了mixins的这两个问题。Composition API的优点
- 除了在逻辑复用方面的优势,也会有更好的类型支持
- 因为他们都是一些函数,在调用函数时,自然所有的类型就被推导出来了,不像
Options API所有的东西使用this Composition API对tree-shaking友好,代码更容易压缩