在 FiberScheduler 中的全局变量

  1. // Used to ensure computeUniqueAsyncExpiration is monotonically increasing.
  2. let lastUniqueAsyncExpiration: number = 0
  3. // Represents the expiration time that incoming updates should use. (If this
  4. // is NoWork, use the default strategy: async updates in async mode, sync
  5. // updates in sync mode.)
  6. let expirationContext: ExpirationTime = NoWork
  7. let isWorking: boolean = false
  8. // The next work in progress fiber that we're currently working on.
  9. let nextUnitOfWork: Fiber | null = null
  10. let nextRoot: FiberRoot | null = null
  11. // The time at which we're currently rendering work.
  12. let nextRenderExpirationTime: ExpirationTime = NoWork
  13. let nextLatestAbsoluteTimeoutMs: number = -1
  14. let nextRenderDidError: boolean = false
  15. // The next fiber with an effect that we're currently committing.
  16. let nextEffect: Fiber | null = null
  17. let isCommitting: boolean = false
  18. let legacyErrorBoundariesThatAlreadyFailed: Set<mixed> | null = null
  19. // Used for performance tracking.
  20. let interruptedBy: Fiber | null = null

lastUniqueAsyncExpiration

createBatch中有调用,但是没发现createBatch在哪里被调用,所以,目前没发现什么作用。

  1. function computeUniqueAsyncExpiration(): ExpirationTime {
  2. const currentTime = requestCurrentTime()
  3. let result = computeAsyncExpiration(currentTime)
  4. if (result <= lastUniqueAsyncExpiration) {
  5. result = lastUniqueAsyncExpiration + 1
  6. }
  7. lastUniqueAsyncExpiration = result
  8. return lastUniqueAsyncExpiration
  9. }

expirationContext

保存创建expirationTime的上下文,在syncUpdatesdeferredUpdates中分别被设置为SyncAsyncExpirationTime,在有这个上下文的时候任何更新计算出来的过期时间都等于expirationContext
比如调用ReactDOM.flushSync的时候,他接受的回调中的setState

isWorking

commitRootrenderRoot开始都会设置为true,然后在他们各自阶段结束的时候都重置为false
用来标志是否当前有更新正在进行,不区分阶段

isCommitting

commitRoot开头设置为true,结束之后设置为false
用来标志是否处于commit阶段

nextUnitOfWork

用于记录render阶段Fiber树遍历过程中下一个需要执行的节点。
resetStack中分别被重置
他只会指向workInProgress

nextRoot & nextRenderExpirationTime

用于记录下一个将要渲染的root节点下一个要渲染的任务的
renderRoot开始的时候赋值,需要符合如下条件才会重新赋值

  1. if (
  2. expirationTime !== nextRenderExpirationTime ||
  3. root !== nextRoot ||
  4. nextUnitOfWork === null
  5. ) {
  6. resetStack()
  7. nextRoot = root
  8. nextRenderExpirationTime = expirationTime
  9. nextUnitOfWork = createWorkInProgress(
  10. nextRoot.current,
  11. null,
  12. nextRenderExpirationTime,
  13. )
  14. }

解释一下就是说,只有这一次调用renderRoot的时候,有

  • 新的root要渲染
  • 相同的root但是任务有不同优先级的任务要渲染
  • 或者在老的任务上没有下一个节点需要渲染了

    nextLatestAbsoluteTimeoutMs

    用来记录Suspense组件何时重新尝试渲染,涉及复杂的公式,这里就不详细说了。
    可以看renderRoot

    nextRenderDidError

    用于记录当前render流程是否有错误产生
    resetStack重置为false
    throwException中如果发现了不能直接处理的错误(除了 Promise 之外),那么就调用renderDidError设置为true

    nextEffect

    用于commit阶段记录firstEffect -> lastEffect链遍历过程中的每一个Fiber

    interruptedBy

    给开发工具用的,用来展示被哪个节点打断了异步任务

    跟调度有关的全局变量

    ReactFiberScheduler.js 1797-1826

  1. // Linked-list of roots
  2. let firstScheduledRoot: FiberRoot | null = null
  3. let lastScheduledRoot: FiberRoot | null = null
  4. let callbackExpirationTime: ExpirationTime = NoWork
  5. let callbackID: *
  6. let isRendering: boolean = false
  7. let nextFlushedRoot: FiberRoot | null = null
  8. let nextFlushedExpirationTime: ExpirationTime = NoWork
  9. let lowestPriorityPendingInteractiveExpirationTime: ExpirationTime = NoWork
  10. let deadlineDidExpire: boolean = false
  11. let hasUnhandledError: boolean = false
  12. let unhandledError: mixed | null = null
  13. let deadline: Deadline | null = null
  14. let isBatchingUpdates: boolean = false
  15. let isUnbatchingUpdates: boolean = false
  16. let isBatchingInteractiveUpdates: boolean = false
  17. let completedBatches: Array<Batch> | null = null
  18. let originalStartTimeMs: number = now()
  19. let currentRendererTime: ExpirationTime = msToExpirationTime(
  20. originalStartTimeMs,
  21. )
  22. let currentSchedulerTime: ExpirationTime = currentRendererTime
  23. // Use these to prevent an infinite loop of nested updates
  24. const NESTED_UPDATE_LIMIT = 50
  25. let nestedUpdateCount: number = 0
  26. let lastCommittedRootDuringThisBatch: FiberRoot | null = null

firstScheduledRoot & lastScheduledRoot

用于存放有任务的所有root的单列表结构

  • findHighestPriorityRoot用来检索优先级最高的root
  • addRootToSchedule中会修改

findHighestPriorityRoot中会判断rootexpirationTime,并不会直接删除root

callbackExpirationTime & callbackID

记录请求ReactScheduler的时候用的过期时间,如果在一次调度期间有新的调度请求进来了,而且优先级更高,那么需要取消上一次请求,如果更低则无需再次请求调度。
callbackIDReactScheduler返回的用于取消调度的 ID

isRendering

performWorkOnRoot开始设置为true,结束的时候设置为false,表示进入渲染阶段,这是包含rendercommit阶段的。

nextFlushedRoot & nextFlushedExpirationTime

用来标志下一个需要渲染的root和对应的expirtaionTime,注意:

  • 通过findHighestPriorityRoot找到最高优先级的
  • 通过flushRoot会直接设置指定的,不进行筛选

    lowestPriorityPendingInteractiveExpirationTime

    类似expirationContext,用来存储interactiveUpdates产生的最小的expirationTime,在下一次外部指定的interactiveUpdates情况下会强制输出上一次的interactiveUpdates因为interactiveUpdates主要是用户输入之类的操作,如果不及时输出会给用户造成断层感
    可以通过调用ReactDOM.unstable_interactiveUpdates来实现以上目的

    deadline & deadlineDidExpire

    deadlineReactScheduler中返回的时间片调度信息对象
    用于记录是否时间片调度是否过期,在shouldYield根据deadline是否过期来设置

    hasUnhandledError & unhandledError

    Profiler调试相关

    isBatchingUpdates & isUnbatchingUpdates & isBatchingInteractiveUpdates

    batchedUpdatesunBatchedUpdatesdeferredUpdatesinteractiveUpdates等这些方法用来存储更新产生的上下文的变量

    originalStartTimeMs

    固定值,js 加载完一开始计算的结果

    currentRendererTime & currentSchedulerTime

    计算从页面加载到现在为止的毫秒数,后者会在isRendering === true的时候用作固定值返回,不然每次requestCurrentTime都会重新计算新的时间。

    nestedUpdateCount & lastCommittedRootDuringThisBatch

    用来记录是否有嵌套得再生命周期方法中产生更新导致应用无限循环更新得计数器,用于提醒用户书写的不正确的代码。