一:性能优化
1. 源码体积优化
- 移除一些冷门的 feature(比如 filter、inline-template 等)
- 引入 tree-shaking 的技术,减少打包体积(tree-shaking 依赖 ES2015 模块语法的静态结构(即 import 和 export),通过编译阶段的静态分析,找到没有引入的模块并打上标记。)
2. 数据劫持优化
1.Object.defineProperty:
- 只能对属性进行劫持,需要递归遍历对象的每个属性,执行Object.defineProperty把每一层对象数据都变成响应式的(如果定义的响应式数据过于复杂,会有很大的性能负担)
- 不能检测对象属性的添加和删除(需要重新遍历)
2.Proxy
- 在getter中去递归响应式,真正访问到的内部对象才会变成响应式,而不是无脑递归,提升了性能
- 劫持的是整个对象,能检测到对象属性的添加和删除
3.编译优化
vue2.x
- vue2.x 的数据更新并触发重新渲染的粒度是组件级的,虽然 vue 能保证触发更新的组件的最小化,但仍需要遍历该组件的整个 vnode树(即使只有一个动态节点),所以很多diff和遍历其实是不需要的,这就导致 vnode 的性能跟
模板大小
正相关,跟动态节点的数量
无关。 (当组件中只有少量动态节点时,这些遍历都是性能的浪费)
vue3.x
- 通过编译阶段对静态模板的分析,编译生成了 Block tree。 Block tree 是一个将模板基于动态节点指令切割的嵌套区块,每个区块内部的节点结构是固定的,而且每个区块只需要以一个 Array 在追踪自身包含的动态节点。借助 Block tree,Vue.js 将 vnode
更新性能
由与模版整体大小相关提升为与动态内容的数量相关
,这是一个非常大的性能突破。 - 除此之外,Vue.js 3.0 在编译阶段还包含了对 Slot 的编译优化、事件侦听函数的缓存优化,并且在运行时重写了 diff 算法
二:语法 API 优化:Composition API
1. 优化逻辑组织
Options API
- Options API 的设计是按照 methods、computed、data、props 这些不同的选项分类,当组件小的时候,这种分类方式一目了然;但是在大型组件中,一个组件可能有多个逻辑关注点,当使用 Options API 的时候,每一个关注点都有自己的 Options,如果需要修改一个逻辑点关注点,就需要在单个文件中不断上下切换和寻找。
Composition API
- 它有一个很好的机制去解决这样的问题,就是将某个逻辑关注点相关的代码全都放在一个函数里,这样当需要修改一个功能时,就不再需要在文件中跳来跳去。
2. 优化逻辑复用
vue2.x 中使用单个 mixin 似乎问题不大,但是当我们一个组件混入大量不同的 mixins
的时候,会存在两个非常明显的问题:命名冲突和数据来源不清晰。
- 首先每个 mixin 都可以定义自己的 props、data,它们之间是无感的,所以很容易定义相同的变量,导致命名冲突。
- 另外对组件而言,如果模板中使用不在当前组件中定义的变量,那么就会不太容易知道这些变量在哪里定义的,这就是数据来源不清晰。
三:源码优化
1. 有类型的 JavaScript:Flow -> TypeScript
Flow
- 对于复杂的框架项目开发,使用类型语言非常有利于代码的维护,因为它可以在编码期间帮你做类型检查,避免一些因类型问题导致的错误;也可以利于它去定义接口的类型,利于 IDE 对变量类型的推导。
- Flow对于一些复杂场景类型的检查,支持的并不好。
TypeScript
- TypeScript 提供了更好的类型检查,能支持复杂的类型推导
- 由于源码就使用 TypeScript 编写,也省去了单独维护 d.ts 文件的麻烦
- 就整个 TypeScript 的生态来看,TypeScript 团队也是越做越好,TypeScript 本身保持着一定频率的迭代和更新,支持的 feature 也越来越多。