Vue 3 源码解读

目录结构

Vue 3的源码采用monorepo的方式组织,使用pnpm进行包管理,主要包含以下核心模块:

  • reactivity: 响应式系统
  • runtime-core: 与平台无关的运行时核心
  • runtime-dom: 浏览器平台特定的运行时
  • compiler-core: 与平台无关的编译器核心
  • compiler-dom: 浏览器平台特定的编译器实现
  • compiler-sfc: 单文件组件(.vue文件)编译器
  • shared: 共享工具函数
  • vue: 完整版本,包含运行时和编译器

一、响应式系统 (reactivity)

Vue 3的响应式系统是整个框架的核心,它基于ES6的Proxy实现,相比Vue 2使用的Object.defineProperty有了质的飞跃。

1.1 核心API实现原理

reactive

reactive函数是创建响应式对象的主要入口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// packages/reactivity/src/reactive.ts (简化版)
export function reactive(target: object) {
// 如果是只读对象,直接返回
if (isReadonly(target)) {
return target
}
// 创建响应式代理
return createReactiveObject(
target,
false,
mutableHandlers,
mutableCollectionHandlers,
reactiveMap
)
}

function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>,
proxyMap: WeakMap<Target, any>
) {
// 如果目标不是对象,直接返回
if (!isObject(target)) {
return target
}

// 如果已经是响应式对象,直接返回
if (
target[ReactiveFlags.RAW] &&
!(isReadonly && target[ReactiveFlags.IS_REACTIVE])
) {
return target
}

// 检查缓存中是否已存在对应的代理
const existingProxy = proxyMap.get(target)
if (existingProxy) {
return existingProxy
}

// 获取目标的类型
const targetType = getTargetType(target)
// 如果目标类型无效,直接返回原对象
if (targetType === TargetType.INVALID) {
return target
}

// 根据目标类型选择不同的handlers
const proxy = new Proxy(
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)

// 缓存代理对象
proxyMap.set(target, proxy)
return proxy
}

effect

effect函数用于注册副作用函数,当响应式数据变化时会自动执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// packages/reactivity/src/effect.ts (简化版)
export function effect<T = any>(
fn: () => T,
options?: ReactiveEffectOptions
): ReactiveEffectRunner {
// 如果fn已经是一个effect函数,获取原始函数
if ((fn as ReactiveEffectRunner).effect) {
fn = (fn as ReactiveEffectRunner).effect.fn
}

// 创建响应式effect
const _effect = new ReactiveEffect(fn)

// 合并选项
if (options) {
extend(_effect, options)
if (options.scope) recordEffectScope(_effect, options.scope)
}

// 如果不是懒执行,立即运行
if (!options || !options.lazy) {
_effect.run()
}

// 返回绑定了this的run函数
const runner = _effect.run.bind(_effect) as ReactiveEffectRunner
runner.effect = _effect
return runner
}

export class ReactiveEffect<T = any> {
active = true
deps: Dep[] = []
parent: ReactiveEffect | undefined = undefined

constructor(
public fn: () => T,
public scheduler: EffectScheduler | null = null,
scope?: EffectScope
) {
recordEffectScope(this, scope)
}

run() {
if (!this.active) {
return this.fn()
}

try {
// 设置当前活动的effect
activeEffect = this
// 执行函数前,将其标记为允许追踪
trackOpBit = 1 << ++effectTrackDepth

// 如果嵌套深度小于最大值,使用位操作追踪
if (effectTrackDepth <= maxMarkerBits) {
initDepMarkers(this)
} else {
// 否则清除所有依赖
cleanupEffect(this)
}

// 执行函数,此时会触发代理的getter,从而收集依赖
return this.fn()
} finally {
// 恢复状态
if (effectTrackDepth <= maxMarkerBits) {
finalizeDepMarkers(this)
}

trackOpBit = 1 << --effectTrackDepth
activeEffect = this.parent
this.parent = undefined
}
}

stop() {
if (this.active) {
cleanupEffect(this)
if (this.onStop) {
this.onStop()
}
this.active = false
}
}
}

ref

ref函数用于创建基本类型的响应式引用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// packages/reactivity/src/ref.ts (简化版)
export function ref(value?: unknown) {
return createRef(value, false)
}

function createRef(rawValue: unknown, shallow: boolean) {
// 如果已经是ref,直接返回
if (isRef(rawValue)) {
return rawValue
}
return new RefImpl(rawValue, shallow)
}

class RefImpl<T> {
private _value: T
private _rawValue: T

public dep?: Dep = undefined
public readonly __v_isRef = true

constructor(value: T, public readonly __v_isShallow: boolean) {
this._rawValue = __v_isShallow ? value : toRaw(value)
this._value = __v_isShallow ? value : toReactive(value)
}

get value() {
// 追踪依赖
trackRefValue(this)
return this._value
}

set value(newVal) {
// 获取原始值进行比较
newVal = this.__v_isShallow ? newVal : toRaw(newVal)
if (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal
this._value = this.__v_isShallow ? newVal : toReactive(newVal)
// 触发更新
triggerRefValue(this, newVal)
}
}
}

1.2 依赖收集与触发更新

Vue 3的响应式系统核心在于依赖收集(track)和触发更新(trigger):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// packages/reactivity/src/effect.ts (简化版)
// 依赖收集
export function track(target: object, type: TrackOpTypes, key: unknown) {
if (shouldTrack && activeEffect) {
// 获取target对应的依赖Map
let depsMap = targetMap.get(target)
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()))
}

// 获取key对应的依赖集合
let dep = depsMap.get(key)
if (!dep) {
depsMap.set(key, (dep = createDep()))
}

// 收集依赖
trackEffects(dep)
}
}

// 触发更新
export function trigger(
target: object,
type: TriggerOpTypes,
key?: unknown,
newValue?: unknown,
oldValue?: unknown,
oldTarget?: Map<unknown, unknown> | Set<unknown>
) {
// 获取target对应的依赖Map
const depsMap = targetMap.get(target)
if (!depsMap) {
// 没有依赖,直接返回
return
}

// 收集需要触发的effects
let deps: (Dep | undefined)[] = []

// 根据操作类型收集相关依赖
if (type === TriggerOpTypes.CLEAR) {
// 清除操作,触发所有依赖
deps = [...depsMap.values()]
} else if (key === 'length' && isArray(target)) {
// 数组length变化
depsMap.forEach((dep, key) => {
if (key === 'length' || key >= (newValue as number)) {
deps.push(dep)
}
})
} else {
// 普通属性变化
if (key !== void 0) {
deps.push(depsMap.get(key))
}

// 根据操作类型添加额外依赖
switch (type) {
case TriggerOpTypes.ADD:
if (!isArray(target)) {
deps.push(depsMap.get(ITERATE_KEY))
if (isMap(target)) {
deps.push(depsMap.get(MAP_KEY_ITERATE_KEY))
}
} else if (isIntegerKey(key)) {
// 数组索引添加,触发length相关依赖
deps.push(depsMap.get('length'))
}
break
case TriggerOpTypes.DELETE:
if (!isArray(target)) {
deps.push(depsMap.get(ITERATE_KEY))
if (isMap(target)) {
deps.push(depsMap.get(MAP_KEY_ITERATE_KEY))
}
}
break
case TriggerOpTypes.SET:
if (isMap(target)) {
deps.push(depsMap.get(ITERATE_KEY))
}
break
}
}

// 触发收集的effects
if (deps.length === 1) {
if (deps[0]) {
triggerEffects(deps[0])
}
} else {
const effects: ReactiveEffect[] = []
for (const dep of deps) {
if (dep) {
effects.push(...dep)
}
}
triggerEffects(createDep(effects))
}
}

二、组件系统与渲染机制

Vue 3的组件系统是构建用户界面的核心,它基于虚拟DOM实现高效的渲染。

2.1 虚拟DOM (VNode)

VNode是Vue中虚拟DOM节点的表示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// packages/runtime-core/src/vnode.ts (简化版)
export const createVNode = (
type: VNodeTypes,
props: VNodeProps | null = null,
children: unknown = null,
patchFlag: number = 0,
dynamicProps: string[] | null = null,
isBlockNode = false
): VNode => {
// 处理class和style规范化
if (props) {
// 规范化class
if (props.class != null) {
props.class = normalizeClass(props.class)
}

// 规范化style
if (props.style != null) {
props.style = normalizeStyle(props.style)
}
}

// 根据type类型确定shapeFlag
const shapeFlag = isString(type)
? ShapeFlags.ELEMENT
: isObject(type)
? ShapeFlags.STATEFUL_COMPONENT
: isFunction(type)
? ShapeFlags.FUNCTIONAL_COMPONENT
: 0

// 创建VNode对象
return createBaseVNode(
type,
props,
children,
patchFlag,
dynamicProps,
shapeFlag,
isBlockNode,
true
)
}

2.2 组件实例创建与生命周期

组件实例的创建过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// packages/runtime-core/src/component.ts (简化版)
export function createComponentInstance(
vnode: VNode,
parent: ComponentInternalInstance | null,
suspense: SuspenseBoundary | null
) {
// 获取组件类型和上下文
const type = vnode.type as ConcreteComponent
const appContext = (parent ? parent.appContext : vnode.appContext) || emptyAppContext

// 创建组件实例对象
const instance: ComponentInternalInstance = {
uid: uid++,
vnode,
type,
parent,
appContext,
root: null!, // 稍后设置
next: null,
subTree: null!, // 稍后设置
effect: null!,
update: null!, // 稍后设置
scope: new EffectScope(true /* detached */),
render: null,
proxy: null,
exposed: null,
exposeProxy: null,
withProxy: null,
provides: parent ? parent.provides : Object.create(appContext.provides),
accessCache: null!,
renderCache: [],

// 组件状态
components: null,
directives: null,
propsOptions: normalizePropsOptions(type, appContext),
emitsOptions: normalizeEmitsOptions(type, appContext),
emit: null!, // 稍后设置
emitted: null,
propsDefaults: EMPTY_OBJ,
inheritAttrs: type.inheritAttrs,
ctx: EMPTY_OBJ,
data: EMPTY_OBJ,
props: EMPTY_OBJ,
attrs: EMPTY_OBJ,
slots: EMPTY_OBJ,
refs: EMPTY_OBJ,
setupState: EMPTY_OBJ,
setupContext: null,

// 生命周期钩子
suspense,
suspenseId: suspense ? suspense.pendingId : 0,
asyncDep: null,
asyncResolved: false,
isMounted: false,
isUnmounted: false,
isDeactivated: false,
bc: null,
c: null,
bm: null,
m: null,
bu: null,
u: null,
um: null,
bum: null,
da: null,
a: null,
rtg: null,
rtc: null,
ec: null,
sp: null
}

// 开发环境下使用代理对象作为上下文
instance.ctx = { _: instance }
instance.root = parent ? parent.root : instance
instance.emit = emit.bind(null, instance)

return instance
}

2.3 组件挂载与更新

组件的挂载和更新过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// packages/runtime-core/src/renderer.ts (简化版)
const mountComponent = (
initialVNode: VNode,
container: RendererElement,
anchor: RendererNode | null,
parentComponent: ComponentInternalInstance | null,
parentSuspense: SuspenseBoundary | null,
isSVG: boolean,
optimized: boolean
) => {
// 创建组件实例
const instance = (initialVNode.component = createComponentInstance(
initialVNode,
parentComponent,
parentSuspense
))

// 设置组件实例
setupComponent(instance)

// 设置并运行带有副作用的渲染函数
setupRenderEffect(
instance,
initialVNode,
container,
anchor,
parentSuspense,
isSVG,
optimized
)
}

const setupRenderEffect = (
instance: ComponentInternalInstance,
initialVNode: VNode,
container: RendererElement,
anchor: RendererNode | null,
parentSuspense: SuspenseBoundary | null,
isSVG: boolean,
optimized: boolean
) => {
const componentUpdateFn = () => {
if (!instance.isMounted) {
// 挂载组件
const { bm, m, parent } = instance

// beforeMount 钩子
if (bm) {
invokeArrayFns(bm)
}

// 渲染组件子树
const subTree = (instance.subTree = renderComponentRoot(instance))

// 挂载子树
patch(
null,
subTree,
container,
anchor,
instance,
parentSuspense,
isSVG
)

// 设置元素引用
initialVNode.el = subTree.el

// mounted 钩子
if (m) {
queuePostRenderEffect(m, parentSuspense)
}

// 标记为已挂载
instance.isMounted = true
} else {
// 更新组件
let { next, bu, u, parent, vnode } = instance

// 如果有待更新的VNode
if (next) {
next.el = vnode.el
updateComponentPreRender(instance, next, optimized)
} else {
next = vnode
}

// beforeUpdate 钩子
if (bu) {
invokeArrayFns(bu)
}

// 渲染新的子树
const nextTree = renderComponentRoot(instance)
const prevTree = instance.subTree
instance.subTree = nextTree

// 更新子树
patch(
prevTree,
nextTree,
hostParentNode(prevTree.el!)!,
getNextHostNode(prevTree),
instance,
parentSuspense,
isSVG
)

// 更新引用
next.el = nextTree.el

// updated 钩子
if (u) {
queuePostRenderEffect(u, parentSuspense)
}
}
}

// 创建响应式effect
const effect = (instance.effect = new ReactiveEffect(
componentUpdateFn,
() => queueJob(update),
instance.scope
))

// 组件更新函数
const update = (instance.update = () => effect.run())

// 执行更新
update()
}

三、Composition API 实现

Composition API是Vue 3的一大特色,它提供了一种更灵活的组织组件逻辑的方式。

3.1 setup函数

setup函数是Composition API的入口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// packages/runtime-core/src/component.ts (简化版)
export function setupComponent(
instance: ComponentInternalInstance,
isSSR = false
) {
const { props, children } = instance.vnode

// 处理props
initProps(instance, props, isSSR)
// 处理slots
initSlots(instance, children)

// 设置有状态的组件
const setupResult = setupStatefulComponent(instance, isSSR)
return setupResult
}

function setupStatefulComponent(
instance: ComponentInternalInstance,
isSSR: boolean
) {
const Component = instance.type as ComponentOptions

// 创建渲染上下文代理
instance.proxy = markRaw(new Proxy(instance.ctx, PublicInstanceProxyHandlers))

// 获取setup函数
const { setup } = Component
if (setup) {
// 创建setup上下文
const setupContext = (instance.setupContext =
setup.length > 1 ? createSetupContext(instance) : null)

// 设置当前实例
setCurrentInstance(instance)
// 暂停依赖收集
pauseTracking()

// 调用setup函数
const setupResult = callWithErrorHandling(
setup,
instance,
ErrorCodes.SETUP_FUNCTION,
[instance.props, setupContext]
)

// 恢复依赖收集
resetTracking()
// 清除当前实例
unsetCurrentInstance()

// 处理setup返回值
if (isPromise(setupResult)) {
// 异步setup
setupResult.then(unsetCurrentInstance, unsetCurrentInstance)

if (isSSR) {
// 服务端渲染处理
return setupResult
.then((resolvedResult) => {
handleSetupResult(instance, resolvedResult, isSSR)
})
.catch(e => {
handleError(e, instance, ErrorCodes.SETUP_FUNCTION)
})
} else {
// 客户端异步组件处理
instance.asyncDep = setupResult
}
} else {
// 同步setup
handleSetupResult(instance, setupResult, isSSR)
}
} else {
// 无setup函数,完成组件设置
finishComponentSetup(instance, isSSR)
}
}

3.2 核心Composition API实现

ref和reactive

前面已经介绍过,这里不再重复。

computed

computed函数用于创建计算属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// packages/reactivity/src/computed.ts (简化版)
export function computed<T>(
getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,
debugOptions?: DebuggerOptions,
isSSR = false
) {
let getter: ComputedGetter<T>
let setter: ComputedSetter<T>

// 规范化参数
const onlyGetter = isFunction(getterOrOptions)
if (onlyGetter) {
getter = getterOrOptions
setter = NOOP
} else {
getter = getterOrOptions.get
setter = getterOrOptions.set
}

// 创建计算属性实例
const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR)

return cRef as any
}

class ComputedRefImpl<T> {
public dep?: Dep = undefined

private _value!: T
public readonly effect: ReactiveEffect<T>

public readonly __v_isRef = true
public readonly [ReactiveFlags.IS_READONLY]: boolean = false

public _dirty = true
public _cacheable: boolean

constructor(
getter: ComputedGetter<T>,
private readonly _setter: ComputedSetter<T>,
isReadonly: boolean,
isSSR: boolean
) {
// 创建effect
this.effect = new ReactiveEffect(getter, () => {
// 当依赖变化时,标记为脏
if (!this._dirty) {
this._dirty = true
// 触发更新
triggerRefValue(this)
}
})
this.effect.computed = this
this.effect.active = this._cacheable = !isSSR
this[ReactiveFlags.IS_READONLY] = isReadonly
}

get value() {
// 如果是可缓存的,且有依赖追踪
const self = toRaw(this)
// 追踪依赖
trackRefValue(self)
// 如果脏或者不可缓存,重新计算
if (self._dirty || !self._cacheable) {
self._dirty = false
self._value = self.effect.run()!
}
return self._value
}

set value(newValue: T) {
this._setter(newValue)
}
}

watch和watchEffect

watchwatchEffect用于监听响应式数据变化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// packages/runtime-core/src/apiWatch.ts (简化版)
export function watch<T = any, Immediate extends Readonly<boolean> = false>(
source: T | WatchSource<T>,
cb: any,
options?: WatchOptions<Immediate>
): WatchStopHandle {
return doWatch(source as any, cb, options)
}

export function watchEffect(
effect: WatchEffect,
options?: WatchOptionsBase
): WatchStopHandle {
return doWatch(effect, null, options)
}

function doWatch(
source: WatchSource | WatchSource[] | WatchEffect | object,
cb: WatchCallback | null,
{ immediate, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ
): WatchStopHandle {
// 处理source
let getter: () => any
let forceTrigger = false
let isMultiSource = false

if (isRef(source)) {
// ref类型
getter = () => source.value
forceTrigger = isShallow(source)
} else if (isReactive(source)) {
// reactive类型
getter = () => source
deep = true
} else if (isArray(source)) {
// 数组类型
isMultiSource = true
forceTrigger = source.some(s => isReactive(s) || isShallow(s))
getter = () =>
source.map(s => {
if (isRef(s)) {
return s.value
} else if (isReactive(s)) {
return traverse(s)
} else if (isFunction(s)) {
return callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER)
} else {
return s
}
})
} else if (isFunction(source)) {
// 函数类型
if (cb) {
// watch(getter, cb)
getter = () =>
callWithErrorHandling(source, instance, ErrorCodes.WATCH_GETTER)
} else {
// watchEffect
getter = () => {
if (instance && instance.isUnmounted) {
return
}
if (cleanup) {
cleanup()
}
return callWithAsyncErrorHandling(
source,
instance,
ErrorCodes.WATCH_CALLBACK,
[onCleanup]
)
}
}
} else {
// 无效source
getter = NOOP
}

// 处理deep选项
if (cb && deep) {
const baseGetter = getter
getter = () => traverse(baseGetter())
}

// 清理函数
let cleanup: () => void
let onCleanup: OnCleanup = (fn: () => void) => {
cleanup = effect.onStop = () => {
callWithErrorHandling(fn, instance, ErrorCodes.WATCH_CLEANUP)
}
}

// 旧值
let oldValue = isMultiSource
? new Array((source as []).length).fill(INITIAL_WATCHER_VALUE)
: INITIAL_WATCHER_VALUE

// 调度器函数
const job: SchedulerJob = () => {
if (!effect.active) {
return
}
if (cb) {
// watch(source, cb)
const newValue = effect.run()
if (
deep ||
forceTrigger ||
(isMultiSource
? (newValue as any[]).some((v, i) =>
hasChanged(v, (oldValue as any[])[i])
)
: hasChanged(newValue, oldValue))
) {
// 清理旧的副作用
if (cleanup) {
cleanup()
}
// 调用回调
callWithAsyncErrorHandling(cb, instance, ErrorCodes.WATCH_CALLBACK, [
newValue,
oldValue === INITIAL_WATCHER_VALUE
? undefined
: isMultiSource && oldValue[0] === INITIAL_WATCHER_VALUE
? []
: oldValue,
onCleanup
])
// 更新旧值
oldValue = newValue
}
} else {
// watchEffect
effect.run()
}
}

// 设置调度器优先级
job.allowRecurse = !!cb

// 根据flush选项设置调度器
let scheduler: EffectScheduler
if (flush === 'sync') {
// 同步调度
scheduler = job as any
} else if (flush === 'post') {
// 后置调度(组件更新后)
scheduler = () => queuePostRenderEffect(job, instance && instance.suspense)
} else {
// 默认:'pre',前置调度(组件更新前)
job.pre = true
if (instance) job.id = instance.uid
scheduler = () => queueJob(job)
}

// 创建effect
const effect = new ReactiveEffect(getter, scheduler)

// 初始运行
if (cb) {
if (immediate) {
job()
} else {
oldValue = effect.run()
}
} else if (flush === 'post') {
queuePostRenderEffect(
effect.run.bind(effect),
instance && instance.suspense
)
} else {
effect.run()
}

// 返回停止函数
return () => {
effect.stop()
if (instance && instance.scope) {
remove(instance.scope.effects!, effect)
}
}
}

四、编译优化

Vue 3在编译阶段引入了许多优化,提高了渲染性能。

4.1 静态提升

静态提升是指将静态节点提升到渲染函数之外,避免重复创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 编译前的模板
<div>
<div class="static">Static</div>
<div>{{ dynamic }}</div>
</div>

// Vue 2编译后的渲染函数
function render() {
return h('div', [
h('div', { class: 'static' }, 'Static'),
h('div', this.dynamic)
])
}

// Vue 3编译后的渲染函数(带静态提升)
const hoisted = h('div', { class: 'static' }, 'Static')
function render() {
return h('div', [
hoisted,
h('div', ctx.dynamic)
])
}

4.2 补丁标记 (PatchFlags)

补丁标记用于标识动态内容的类型,优化更新性能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 编译前的模板
<div id="foo" :class="cls">{{ text }}</div>

// Vue 3编译后的渲染函数
function render() {
return h('div',
{
id: 'foo',
class: ctx.cls // 动态class
},
ctx.text, // 动态文本
PatchFlags.CLASS | PatchFlags.TEXT // 补丁标记
)
}

4.3 块树 (Block Tree)

块树是Vue 3引入的新概念,用于跟踪动态子节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 编译前的模板
<div>
<div>Static</div>
<div v-if="show">Conditional</div>
<div v-for="item in list">{{ item }}</div>
</div>

// Vue 3编译后的渲染函数(简化)
function render() {
return createBlock('div', null, [
createVNode('div', null, 'Static'),
(ctx.show)
? createVNode('div', null, 'Conditional', PatchFlags.DYNAMIC)
: createCommentVNode('v-if'),
renderList(ctx.list, (item) => {
return createVNode('div', null, item, PatchFlags.TEXT)
})
], PatchFlags.STABLE_FRAGMENT)
}

总结

Vue 3源码的核心亮点:

  1. 响应式系统:基于Proxy的全新响应式系统,提供了更好的性能和更完整的响应式覆盖
  2. 组合式API:提供了更灵活的逻辑组织方式,解决了选项式API的限制
  3. 编译优化:静态提升、补丁标记、块树等优化大幅提升了渲染性能
  4. TypeScript支持:源码完全用TypeScript重写,提供了更好的类型推导
  5. 模块化设计:采用monorepo管理,各个模块可以独立使用

Vue 3的源码设计体现了现代前端框架的最佳实践,通过深入理解其实现原理,可以更好地使用Vue 3进行开发。

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器