Vue3.0 所采用的 Composition Api 与 Vue2.x 使用的 Options Api 有什么不同

Options Api

一、Options Api
Options API,即大家常说的选项API,即以vue为后缀的文件,通过定义methods,computed,watch,data等属性与方法,共同处理页面逻辑

Composition Api

组件根据逻辑功能来组织的,一个功能所定义的所有 API 会放在一起(更加的高内聚,低耦合)

即使项目很大,功能很多,我们都能快速的定位到这个功能所用到的所有 API

对比

下面对Composition Api与Options Api进行两大方面的比较
逻辑组织
逻辑复用

组合优于继承

总结

  • 在逻辑组织和逻辑复用方面,Composition API是优于Options API
  • 因为Composition API几乎是函数,会有更好的类型推断。
  • Composition API对 tree-shaking 友好,代码也更容易压缩
  • Composition API中见不到this的使用,减少了this指向不明的情况
  • 如果是小型组件,可以继续使用Options API,也是十分友好的

Vue2.x和Vue3.x diff算法分别说一下

vue2 双端比较

所谓双端比较就是新列表和旧列表两个列表的头与尾互相对比,,在对比的过程中指针会逐渐向内靠拢,直到某一个列表的开始节点大于结束节点的索引,对比停止。

vue3 最长递增子序列

vue3.0diff核心算法

Vue3.0性能提升

编译阶段

因此,Vue3在编译阶段,做了进一步优化。主要有如下:

diff算法优化-PatchFlag(静态标记)

vue3在diff算法中相比vue2增加了静态标记flag,
在 Vue 3.0 中,对 diff 算法进行了优化,在创建虚拟 DOM 时,根据 DOM 内容是否会发生变化,而给予相对应类型的静态标记(PatchFlag),下次发生变化的时候直接找该地方进行比较,其他静态写死的内容根本不用去比较

vue3模板编译网站

标记枚举类型如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export const enum PatchFlags {
TEXT = 1,// 动态的文本节点
CLASS = 1 << 1, // 2 动态的 class
STYLE = 1 << 2, // 4 动态的 style
PROPS = 1 << 3, // 8 动态属性,不包括类名和样式
FULL_PROPS = 1 << 4, // 16 动态 key,当 key 变化时需要完整的 diff 算法做比较
HYDRATE_EVENTS = 1 << 5, // 32 表示带有事件监听器的节点
STABLE_FRAGMENT = 1 << 6, // 64 一个不会改变子节点顺序的 Fragment
KEYED_FRAGMENT = 1 << 7, // 128 带有 key 属性的 Fragment
UNKEYED_FRAGMENT = 1 << 8, // 256 子节点没有 key 的 Fragment
NEED_PATCH = 1 << 9, // 512
DYNAMIC_SLOTS = 1 << 10, // 动态 solt
HOISTED = -1, // 特殊标志是负整数表示永远不会用作 diff
BAIL = -2 // 一个特殊的标志,指代差异算法
}

HoistStatic 静态提升

Vue3中对不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用

这样就免去了重复的创建节点,大型应用会受益于这个改动,免去了重复的创建操作,优化了运行时候的内存占用

事件监听缓存

默认情况下 @click 事件被认为是动态变量,所以每次更新视图的时候都会追踪它的变化。但是正常情况下,我们的 @click 事件在视图渲染前和渲染后,都是同一个事件,基本上不需要去追踪它的变化,所以 Vue 3.0 对此作出了相应的优化叫事件监听缓存
Before

1
2
3
4
5
import { openBlock as _openBlock, createBlock as _createBlock } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("h1", { onClick: _ctx.clickMsg }, "111", 8 /* PROPS */, ["onClick"]))
}

在未开启事件监听缓存的情况下,我们看到这串代码编译后被静态标记为 8,之前讲解过被静态标记的标签就会被拉去做比较,而静态标记 8 对应的是“动态属性,不包括类名和样式”。 @click 被认为是动态属性,所以我们需要开启 Options 下的 cacheHandler 属性
After

1
2
3
4
5
6
7
import { openBlock as _openBlock, createBlock as _createBlock } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("h1", {
onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.clickMsg && _ctx.clickMsg(...args)))
}, "111"))
}

SSR优化

源码体积

相比Vue2,Vue3整体体积变小了,除了移出一些不常用的API,主要是通过Tree shanking实现

任何一个函数,如ref、reavtived、computed等,仅仅在用到的时候才打包,没用到的模块都被摇掉,打包的整体体积变小

响应式系统

vue2中采用 defineProperty来劫持整个对象,然后进行深度遍历所有属性,给每个属性添加getter和setter,实现响应式
vue3采用proxy重写了响应式系统,因为proxy可以对整个对象进行监听,所以不需要深度遍历
可以监听动态属性的添加
可以监听到数组的索引和数组length属性
可以监听删除属性

参考