一、前言

浏览之前,你可能需要对 Vue Reactive 实现有一点了解

可以先阅读下面这两篇文章,可以留意调用函数中的参数

[1. Vue Reactive 响应式原理]( https://www.youdeyiwu.com/posts/1 )

[2. Vue Reactive 依赖追踪和触发更新]( https://www.youdeyiwu.com/posts/2 )

 

 

在 Vue Reactive 的依赖追踪中,使用 ReactiveEffect 类来表示依赖关系:

(packages\reactivity\src\effect.ts)

1export let activeEffect: ReactiveEffect | undefined
2
3export class ReactiveEffect<T = any> {
4  active = true
5  deps: Dep[] = []
6
7  /**
8   * Can be attached after creation
9   * @internal
10   */
11  computed?: ComputedRefImpl<T>
12  /**
13   * @internal
14   */
15  allowRecurse?: boolean
16
17  onStop?: () => void
18  // dev only
19  onTrack?: (event: DebuggerEvent) => void
20  // dev only
21  onTrigger?: (event: DebuggerEvent) => void
22
23  /**
24   * @internal
25   */
26  _dirtyLevel = DirtyLevels.Dirty
27  /**
28   * @internal
29   */
30  _trackId = 0
31  /**
32   * @internal
33   */
34  _runnings = 0
35  /**
36   * @internal
37   */
38  _shouldSchedule = false
39  /**
40   * @internal
41   */
42  _depsLength = 0
43
44  constructor(
45    public fn: () => T,
46    public trigger: () => void,
47    public scheduler?: EffectScheduler,
48    scope?: EffectScope,
49  ) {
50    /// ...
51  }
52
53  public get dirty() {
54    /// ...
55  }
56
57  public set dirty(v) {
58    /// ...
59  }
60
61  run() {
62    /// ...
63  }
64
65  stop() {
66    /// ... 
67  }
68}

 

二、关键字段和方法

  • activeEffect: 当前正在运行的 effect,使用全局变量 activeEffect 来跟踪
  • active: 一个布尔值,表示 effect 是否处于激活状态
  • deps: 一个数组,存储该 effect 依赖的所有依赖集合
  • computed: 可选字段,表示 effect 是否与计算属性相关
  • allowRecurse: 可选字段,表示 effect 是否允许递归触发
  • onStop: 可选字段,在 effect 停止时调用的回调函数
  • onTrack 和 onTrigger: 仅在开发模式下使用的回调函数,用于调试
  • _dirtyLevel: 内部字段,表示 effect 的脏度级别
  • _trackId: 内部字段,用于唯一标识该 effect 的跟踪 ID
  • _runnings: 内部字段,表示该 effect 当前的运行次数
  • _shouldSchedule: 内部字段,表示该 effect 是否需要调度
  • _depsLength: 内部字段,表示该 effect 的依赖数组长度

 

  • run() 方法

设置 _dirtyLevel 为 NotDirty,如果 effect 处于非激活状态,直接执行 fn 并返回结果

否则,保存当前的 shouldTrack 和 activeEffect,并将当前 effect 设置为 activeEffect,然后执行 fn,

最后,恢复之前的 activeEffect 和 shouldTrack 状态

1run() {
2    this._dirtyLevel = DirtyLevels.NotDirty
3    if (!this.active) {
4      return this.fn()
5    }
6    let lastShouldTrack = shouldTrack
7    let lastEffect = activeEffect
8    try {
9      shouldTrack = true
10      activeEffect = this
11      this._runnings++
12      preCleanupEffect(this)
13      return this.fn()
14    } finally {
15      postCleanupEffect(this)
16      this._runnings--
17      activeEffect = lastEffect
18      shouldTrack = lastShouldTrack
19    }
20}

 

三、依赖关系管理

ReactiveEffect 类通过维护一个依赖数组 deps 来跟踪所有依赖于该 effect 的依赖集合

当 effect 被触发时,它会遍历这些依赖集合,并根据脏度级别决定是否需要重新执行 fn

在开发模式下,还会调用调试回调函数 onTrack 和 onTrigger 以提供调试信息。

1export type Dep = Map<ReactiveEffect, number> & {
2    cleanup: () => void
3    computed?: ComputedRefImpl<any>
4}
5
6export class ReactiveEffect<T = any> {
7    /// ...
8    deps: Dep[] = []
9    /// ...
10}

 

四、其他

学习的记录,仅供参考