Mobx 源码分析 - autorun
作用
当用 autorun
时,函数会被立即执行一次,然后每当它的依赖有任何改变,autorun
都会执行一次。
源码解析
生成
name
判断
opts
上是否有scheduler
和delay
。如果都没有,则为true
,否则为false
。runSync 为 true
实例化
Reaction
,传入name
、onInvalidate
函数和错误处理函数。reaction = new Reaction( name, function(this: Reaction) { this.track(reactionRunner); }, opts.onError );
1
2
3
4
5
6
7
runSync 为 false
根据传入参数,生成自己的调度
scheduler
函数实例化
Reaction
,传入name
、onInvalidate
函数和错误处理函数。reaction = new Reaction( name, () => { if (!isScheduled) { isScheduled = true; scheduler(() => { isScheduled = false; if (!reaction.isDisposed) reaction.track(reactionRunner); }); } }, opts.onError );
1
2
3
4
5
6
7
8
9
10
11
12
13
把
this
添加到全局的待处理列表pendingReactions
中开始执行
runReactions
判断当前全局中是否处于处理事务状态或处理反应
reactions
阶段,如果是则返回,什么都不做。否则执行reactionScheduler(runReactionsHelper)
,也就是执行runReactionsHelper
if (globalState.inBatch > 0 || globalState.isRunningReactions) return reactionScheduler(runReactionsHelper)
1
2把全局状态中
isRunningReactions
设为true
,通过pendingReactions
取到所有待处理Reaction
实例,并清空pendingReactions
列表遍历所有实例,针对每一个实例都调用其自身的
runReaction
,遍历结束后把全局isRunningReactions
改为false
runReaction() { // 当前是否已经清除 if (!this.isDisposed) { // 开始处理事务,设置 global.inBatch,令其值 +1 startBatch() this._isScheduled = false // 判断是否需要追踪,当前 dependenciesState 处于 NOT_TRACKING,shouldCompute 会对于此状态返回 true if (shouldCompute(this)) { // 改变当前状态 this._isTrackPending = true try { // 执行传递进来的函数 this.onInvalidate() // 判断当前 _isTrackPending 状态和全局监听器 spy,如果有全局监听器,则发送事件,类型为 scheduled-reaction if (this._isTrackPending && isSpyEnabled()) { // onInvalidate didn't trigger track right away.. spyReport({ name: this.name, type: "scheduled-reaction" }) } } catch (e) { // 错误处理 this.reportExceptionInDerivation(e) } } // 结束处理事务 endBatch() } }
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
onInvalidate
执行 track
函数,参数为 reactionRunner
。
// api/autorun.ts
function(this: Reaction) {
this.track(reactionRunner);
}
// core/reaction.ts
function track(fn){
startBatch()
...
const result = trackDerivedFunction(this, fn, undefined)
...
}
// core/derivation.ts
function trackDerivedFunction(derivation, f, context){
...
result = f.call(context)
...
bindDependencies(derivation)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- 函数内部会调用
startBatch
,再次使global.inBatch
值+1
- 判断是否有监听器
spy
,有则发送事件,类型为reaction
,并记录当前时间 - 设置当前状态
_isRunning
为true
- 改变当前依赖状态
dependenciesState
为UP_TO_DATE
,UP_TO_DATE
意味着值是新的 - 取出传入对象的
observing
属性值,如果有值,则遍历,把每一项的lowestObserverState
都设为UP_TO_DATE
- 把传入的
derivation
设置到全局对象上,同时给derivation
新增属性 - 判断是否需要捕获错误
globalState.disableErrorBoundaries
,调用传入的函数,收集新的依赖 - 把全局对象
trackingDerivation
恢复原状 - 更新依赖关系,针对新的依赖,增加监听者,对于旧的依赖且新的依赖中也没有使用到的,则移除此依赖,并执行
onBecomeStale
,更新所有的依赖项 - 根据
this.isDisposed
判断需要清除autorun
- 如有监听器,则向监听器发送此次
reaction
和derivation
耗时 - 结束事务处理,移除监听者,并把清除监听状态