【Vue3】Vue3对比Vue2的优点

2022/12/05 12:15:132022/12/01 12:13:17

  • 体积更小,按需编译(支持 Tree-shaking),体积 Vue2 要更小。
  • 类型推断,更好的支持 ts
  • 高级给予,暴露了更底层的 API 和提供更先进的内置组件。
  • 组合式 API,能够更好的组织逻辑,封装逻辑,复用逻辑。
  • 内部算法优化,效率更高。

性能方面

Vue2 快 1.2~2 倍。

全局 API 按需引入,体积比 Vue2 更小

Vue2 中所有全局 API 都绑定在 Vue.prototype 上,构建工具打包时不会触发 Tree-shaking,这些 API 即使从未调用也会被打包出来。

Vue3 中,通过将大多数全局 API 和内部帮助程序移至 ES 模块导出来,使构建工具能正确进行 Tree-shaking,这样生成的包就不会包含这些未调用的 API

框架的某些部分永远不会 Tree-shaking,因为它们对于任何类型的应用都是必不可少的。我们将这些必不可少的部分的度量标准称为基准尺寸。尽管增加了许多新功能,但 Vue3 的基准大小压缩后约为 10 KB,还不到 Vue2 的一半。

diff 算法优化

Vue2 中的 虚拟dom 是全量的对比(每个节点不论写死的还是动态的都会一层一层比较,这就浪费了大部分时间在对比静态节点上)。

Vue3 新增了静态标记(patchflag)与上次虚拟节点对比时,只对比带有 patchflag 的节点(动态数据所在的节点);可通过 flag 信息得知当前节点要对比的具体内容。

当视图更新时,只对动态节点部分进行 diff 运算,减少了资源的损耗。Patchflag 是个枚举,取值为 1 代表这个元素的文本是动态绑定的,取值为 2 代表元素的 class 是动态绑定的。

hoistStatic 静态提升

文档位置open in new window

Vue2 无论元素是否参与更新,每次都会重新创建然后再渲染。

Vue3 对于不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用,当有足够多连续的静态元素时,它们还会再被压缩为一个“静态 vnode”,其中包含的是这些节点相应的纯 HTML 字符串。。

通过静态提升可以避免每次渲染的时候都要重新创建这些对象,从而大大提高了渲染效率。

cacheHandlers 事件侦听器缓存

Vue2 中,绑定事件每次触发都要重新生成全新的 function 去更新。

Vue3 中提供了 cacheHandlers 事件缓存对象,当 cacheHandlers 开启,会自动生成一个内联函数,同时生成一个静态节点。当事件再次触发时,只需从缓存中调用即可,无需再次更新。

默认情况下 v-on 会被视为动态绑定,所以每次都会追踪它的变化,但是同一个函数没必要追踪变化,直接缓存起来复用即可。

ssr 服务端渲染优化

Vue2 中也是有 SSR 渲染的,但是 Vue3 中的 SSR 渲染相对于 Vue2 来说,性能方面也有对应的提升。

当存在大量静态内容时,这些内容会被当作纯字符串推进一个 buffer 里面,即使存在动态的绑定,会通过模版插值潜入进去。这样会比通过 虚拟dom 来渲染快上很多。

当静态内容大到一个量级的时候,会用 \_createStaticVNode 方法在客户端去生成一个 static node,这些静态 node,会被直接 innerHtml,就不需要再创建对象,然后根据对象渲染。

使用方面

更好的 TS 支持

Vue2 结合 ts 的具体实践中,要用 Vue-class-component 强化 Vue 组件,让 Script 支持 TypeScript 装饰器,用 Vue-property-decorator 来增加更多结合 Vue 特性的装饰器,最终搞的 ts 的组件写法和 js 的组件写法差别挺大。

Vue3 中,量身打造了 defineComponent 函数,使组件在 ts 下,可以更好的利用参数类型推断。

可自定义渲染 API

Vue2 项目架构对于 weex(移动端跨平台方案)和 myVue(小程序上使用)等框架渲染到不同平台不太友好。

Vue3 官方实现的 createApp 会给我们的 template 映射生成 html 代码,但是要是你不想渲染生成到 html,而是要渲染生成到 canvas 之类的不是 html 的代码的时候,可以使用 Custom Renderer API 来定义 createApp 方法。

import { createApp } from "./runtime-render";
import App from "./src/App"; // 根组件
createApp(App).mount("#app");

组合式 API 的优点

1. 更好的逻辑复用

通过组合函数实现更简洁高效的逻辑复用。

文档位置open in new window

Vue2 中使用 mixin 进行逻辑复用,存在以下问题:

  • 数据来源不清晰,引入多个 mixin 时难以维护。
  • 命名空间冲突。

Vue3 将逻辑封装到单个文件中,在需要的地方引入,导出项明确,且不会造成命名冲突。

Vue3 的无渲染组件也可以实现同样的效果,但是相比于组合式函数来说会产生额外的组件实例开销。

2. 更灵活、高内聚的代码组织

文档位置open in new window

使用选项式 API 时,一个业务功能如果用到 computedwatchdata 这些特性,需要在对应的选项中配置,这样就导致逻辑分散,在页面内容增多时维护起来相当麻烦。

使用组合式 API 可以将同一个业务逻辑的代码放在一起,像组织普通的 js 一样组织 vue 逻辑。

3. 更好的 TS 支持

选项式 API 用对象的形式来描述组件,无法提供完整的类型推断。

而组合式 API 通过函数的形式来描述组件,可以更好地提供类型推断。

实现原理方面

用 proxy 重构响应式系统

Vue 的响应式是先进行依赖收集,然后在对应属性被访问或赋值后主动通知来实现的。

Vue2 中监听属性被访问和赋值的方法分两种:

  • 监听对象:通过 Object.defineProperty() 方法给对象的每个属性绑定 gettersetter 实现监听对 Object 的操作。
  • 监听数组:让数组继承一个新的对象作为原型,这个新对象重写了 splice、push 等方法,在这些新方法中监听对 Array 的操作。

Object.defineProperty() 存在的问题:

  • 不能监听数组的变化。
  • 无法监听到添加属性(用 Vue.set() 方法实现添加属性)。
  • 必须遍历对象的每个属性。
  • 必须深层遍历嵌套的对象。

Vue3 使用 proxy 来拦截对属性的访问和赋值行为。Proxy 可以直接监听对象而非属性,支持数组,具有更好的响应式支持。

参考

vue3,对比 vue2 有什么优点?open in new window全局 API treeshakingopen in new windowVue3 对比 Vue2 的优点总结open in new window