# 前言
上一小节我们说到了 Reactive 会在 proxy getter 的时候收集 effect 依赖,在 proxy setter 的时候触发 effect 的执行。那么 effect 副作用函数到底是个什么?以及是如何被收集起来的呢?
# effect
找到源码中关于 effect 部分的定义:
export function effect (fn, options) {
// 如果 fn 已经是一个 effect 函数了,则指向原始函数
if (fn.effect) {
fn = fn.effect.fn
}
// 构造 _effect 实例
const _effect = new ReactiveEffect(fn)
// options 初始化
if (options) {
extend(_effect, options)
if (options.scope) recordEffectScope(_effect, options.scope)
}
// 如有 options 或者 不是懒加载,执行 _effect.run()
if (!options || !options.lazy) {
_effect.run()
}
// 返回 _effect.run
const runner = _effect.run.bind(_effect)
runner.effect = _effect
return runner
}
@前端进阶之旅: 代码已经复制到剪贴板
这个 effect 函数内部核心是通过 ReactiveEffect 类创建了一个 _effect 实例,从代码来看,_effect 上包含了一个 run 函数。默认 effect 是没有传入 options 参数的,所以这里直接执行了 _effect.run()。我们知道,fn 函数是在 effect 函数中的一个入参,比如:
const state = reactive({a: 1})
effect(() => console.log(state.a))
@前端进阶之旅: 代码已经复制到剪贴板
根据上一小节,我们知道因为这里我们访问了 state.a 所以收集了副作用函数,但是需要知道的是这里的 effect 传入的是一个 fn,所以要想访问 state.a 那这个 fn 必须要执行才可以。那是在哪里执行的呢?接下来看一下 ReactiveEffect 的实现:
// 用于记录位于响应上下文中的effect嵌套层次数
let effectTrackDepth = 0
// 二进制位,每一位用于标识当前effect嵌套层级的依赖收集的启用状态
export left trackOpBit = 1
// 表示最大标记的位数
const maxMarkerBits = 30
// 当前活跃的 effect
let activeEffect;
export class ReactiveEffect {
// 用于标识副作用函数是否位于响应式上下文中被执行