Mobx 源码分析 - autorun

当用 autorun 时,函数会被立即执行一次,然后每当它的依赖有任何改变, autorun 都会执行一次。

源码解析

  1. 生成 name

  2. 判断 opts 上是否有 schedulerdelay 。如果都没有,则为 true ,否则为 false

    • runSync 为 true

      1. 实例化 Reaction ,传入 nameonInvalidate 函数和错误处理函数。

        reaction = new Reaction(
            name,
            function(this: Reaction) {
                this.track(reactionRunner);
            },
            opts.onError
        );
        复制代码
    • runSync 为 false

      1. 根据传入参数,生成自己的调度 scheduler 函数

      2. 实例化 Reaction ,传入 nameonInvalidate 函数和错误处理函数。

        reaction = new Reaction(
            name,
            () => {
                if (!isScheduled) {
                    isScheduled = true;
                    scheduler(() => {
                        isScheduled = false;
                        if (!reaction.isDisposed) reaction.track(reactionRunner);
                    });
                }
            },
            opts.onError
        );
        复制代码
  3. this 添加到全局的待处理列表 pendingReactions

  4. 开始执行 runReactions

  5. 判断当前全局中是否处于处理事务状态或处理反应 reactions 阶段,如果是则返回,什么都不做。否则执行 reactionScheduler(runReactionsHelper) ,也就是执行 runReactionsHelper

    if (globalState.inBatch > 0 || globalState.isRunningReactions) return
        reactionScheduler(runReactionsHelper)
    复制代码
  6. 把全局状态中 isRunningReactions 设为 true ,通过 pendingReactions 取到所有待处理 Reaction 实例,并清空 pendingReactions 列表

  7. 遍历所有实例,针对每一个实例都调用其自身的 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()
            }
        }
    复制代码

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. 函数内部会调用 startBatch ,再次使 global.inBatch+1
  2. 判断是否有监听器 spy ,有则发送事件,类型为 reaction ,并记录当前时间
  3. 设置当前状态 _isRunningtrue
  4. 改变当前依赖状态 dependenciesStateUP_TO_DATEUP_TO_DATE 意味着值是新的
  5. 取出传入对象的 observing 属性值,如果有值,则遍历,把每一项的 lowestObserverState 都设为 UP_TO_DATE
  6. 把传入的 derivation 设置到全局对象上,同时给 derivation 新增属性
  7. 判断是否需要捕获错误 globalState.disableErrorBoundaries ,调用传入的函数,收集新的依赖
  8. 把全局对象 trackingDerivation 恢复原状
  9. 更新依赖关系,针对新的依赖,增加监听者,对于旧的依赖且新的依赖中也没有使用到的,则移除此依赖,并执行 onBecomeStale ,更新所有的依赖项
  10. 根据 this.isDisposed 判断需要清除 autorun
  11. 如有监听器,则向监听器发送此次 reactionderivation 耗时
  12. 结束事务处理,移除监听者,并把清除监听状态
我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章