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),也就是执行runReactionsHelperif (globalState.inBatch > 0 || globalState.isRunningReactions) return reactionScheduler(runReactionsHelper)1
2把全局状态中
isRunningReactions设为true,通过pendingReactions取到所有待处理Reaction实例,并清空pendingReactions列表遍历所有实例,针对每一个实例都调用其自身的
runReaction,遍历结束后把全局isRunningReactions改为falserunReaction() { // 当前是否已经清除 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耗时 - 结束事务处理,移除监听者,并把清除监听状态