Skip to content

Latest commit

 

History

History

computeExpirationForFiber

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
function computeExpirationForFiber(currentTime, fiber) {
  let expirationTime = null
  if (expirationContext !== NoWork) {
    // 当通过syncUpdates把任务强制变为最高优先级的时候就会直接走这里
    expirationTime = expirationContext
  } else if (isWorking) {
    if (isCommitting) {
      // 在提交阶段也就是全部fiber都构建完成之后
      // 要把更新真实地渲染到dom上去 这个过程是不能中断的
      // 所以要直接让他变为同步的
      expirationTime = Sync
    } else {
      // 进入这里说明可能是刚才有个异步的任务被中断了
      // 然后现在要重新回来执行刚才那个被中断的任务
      expirationTime = nextRenderExpirationTime
    }
  } else {
    // &是用来看这个mode上是否被添加过ConcurrentMode这个东西
    // 只有当给组件包裹了 <ConcurrentMode></ConcurrentMode> 的时候
    // 才会进入这个逻辑 表示该组件下的所有更新任务都要以低优先级的异步方式更新
    if (fiber.mode & ConcurrentMode) {
      // 给组件包裹了ConcurrentMode组件之后会走到这里
      if (isBatchingInteractiveUpdates) {
        // 进入这里说明是批量更新
        // isBatchingInteractiveUpdates初始默认是false
        // 而在合成事件中 比如onClick等 合成事件会触发 interactiveUpdates方法
        // 这个方法中会将isBatchingInteractiveUpdates和isBatchingUpdates临时置为true
        // 然后才会去调用自己写的真实的想触发的事件 于是在事件中不管执行几次setState
        // 都是按照批量更新进行的(isBatchingUpdates控制是否直接退出还是继续往下去调度Root)
        // 完事儿之后再给isBatchingInteractiveUpdates和isBatchingUpdates置回false

        // 当传的事件中有异步的时候
        // 虽然interactiveUpdates中最终也会触发performSyncWork
        // 但是里头由于还没执行到异步中的setState所以不一定有root
        // 所以可能会直接退出
        // 之后当执行到异步中的setState的时候isBatchingInteractiveUpdates就是false
        // 于是就会走到下面按个Async的逻辑中(在使用了Concurrent组件的前提下 不用Concurrent模式就直接Sync)
        // 不过如果给所有的setState的最外部包裹上batchedUpdates
        // 比如: 
        // setTimeout(() => {
        //   batchedUpdates(() => {
        //     this.setState({ // isBatchingUpdates是true 批量更新
        //       ding: xxx
        //     })
        //     this.setState({ // isBatchingUpdates是true 批量更新
        //       ding: yyy
        //     })
        //     console.log(this.state.ding) // 不能获取
        //   })
        //   console.log(this.state.ding) // 能获取
        // })   

        // 或者当使用addEventListener绑定的事件时 isBatchingInteractiveUpdates也是false
        // 批量更新的优先级相对来说要稍微高一点 比sync低 比async高
        expirationTime = computeInteractiveExpiration(currentTime)
      } else {
        // 总结一下就是
        // 当外层包裹了Concurrent组件的前提下
        // 不把setState放在异步中就会走到上面那个批量更新的逻辑中
        // 而当把setState放在异步中 比如用了setTimeout或放在addEventListener中
        // 都会进入到这个Async的逻辑
        expirationTime = computeAsyncExpiration(currentTime)
      }
      if (nextRoot !== null && expirationTime === nextRenderExpirationTime) {
        // 这块是当异步更新时
        // 比如在对fiber树render了一半的时候讲线程交还给浏览器
        // 然后交还的这段时间内 又触发了一个setState的话
        // 这个时候nextRoot是有值的
        // nextRenderExpirationTime也有值 就是刚才还没有完成的那个更新的截止时间
        // 进到这里的话 说明在交还主线程的这段时间里执行的setState的优先级
        // 和上一把没完成的是一样的 所以就给它减个1 让它的优先级相对来说第一点
        // 这样就优先执行上一把还没整完的那个更新了
        expirationTime -= 1;
      }
    } else {
      // 如果即不是异步也不批量也不是在正在更新fiber树的途中的话
      // 就直接让这个expirationTime变为同步的Sync
      expirationTime = Sync
    }
  }
  return expirationTime
}