【Vue3】Vue3对比Vue2的优点
- 体积更小,按需编译(支持
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 静态提升
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. 更好的逻辑复用
通过组合函数实现更简洁高效的逻辑复用。
Vue2
中使用 mixin
进行逻辑复用,存在以下问题:
- 数据来源不清晰,引入多个
mixin
时难以维护。 - 命名空间冲突。
Vue3
将逻辑封装到单个文件中,在需要的地方引入,导出项明确,且不会造成命名冲突。
Vue3
的无渲染组件也可以实现同样的效果,但是相比于组合式函数来说会产生额外的组件实例开销。
2. 更灵活、高内聚的代码组织
使用选项式 API 时,一个业务功能如果用到 computed
、watch
、data
这些特性,需要在对应的选项中配置,这样就导致逻辑分散,在页面内容增多时维护起来相当麻烦。
使用组合式 API 可以将同一个业务逻辑的代码放在一起,像组织普通的 js 一样组织 vue 逻辑。
3. 更好的 TS 支持
选项式 API 用对象的形式来描述组件,无法提供完整的类型推断。
而组合式 API 通过函数的形式来描述组件,可以更好地提供类型推断。
实现原理方面
用 proxy 重构响应式系统
Vue
的响应式是先进行依赖收集,然后在对应属性被访问或赋值后主动通知来实现的。
Vue2
中监听属性被访问和赋值的方法分两种:
- 监听对象:通过
Object.defineProperty()
方法给对象的每个属性绑定getter
和setter
实现监听对Object
的操作。 - 监听数组:让数组继承一个新的对象作为原型,这个新对象重写了
splice、push
等方法,在这些新方法中监听对Array
的操作。
Object.defineProperty()
存在的问题:
- 不能监听数组的变化。
- 无法监听到添加属性(用
Vue.set()
方法实现添加属性)。 - 必须遍历对象的每个属性。
- 必须深层遍历嵌套的对象。
Vue3
使用 proxy
来拦截对属性的访问和赋值行为。Proxy
可以直接监听对象而非属性,支持数组,具有更好的响应式支持。