Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
const MAX_SIGNED_31_BIT_INT = 1073741823 // (2**31) / 2 - 1
export const NoWork = 0
export const Never = 1
export const Sync = MAX_SIGNED_31_BIT_INT

const UNIT_SIZE = 10
const MAGIC_NUMBER_OFFSET = MAX_SIGNED_31_BIT_INT - 1

export function msToExpirationTime(ms) {
  /*
    (xxx | 0) 意思就是给 xxx 取整
  */
  return MAGIC_NUMBER_OFFSET - ((ms / UNIT_SIZE) | 0)
}

export function expirationTimeToMs(expirationTime) {
  // 用最大的单元减去还剩的单元得到目前执行到第多少次单元
  // 然后乘以尺寸 得到到目前为止对应的时间ms
  return (MAGIC_NUMBER_OFFSET - expirationTime) * UNIT_SIZE
}

// currentTime: 1073741822 - ((当前花费时间 / 10) | 0)
// 这个东西返回结果就相当于
// 1073741822 - ((((1073741822 - currentTime + 500) / 25) | 0) + 1) * 25
// 这个公式的意思吧 主要先看后边这串儿 (((xxx / 25) | 0) + 1) * 25
// xxx / 25 可以理解成这个xxx中有多少个25 可能是个整数 也可能带小数
// 然后给它 |0 了 意思就是取整 也就是说 把 xxx 分成 n 份 每份25 之后把不足25的最后一份扔掉
// 再然后 +1 加了一个1 相当于给 n-1 份变成正好的 n 份 并且每份都是25大小
// 最后 *25 还原成约等于原来 xxx 的大小 不过此时得到的数字可能比 xxx 稍大
// 所以说 两个差距在25以内的数字 最后得到的结果有可能是一样的
// react会把它们当成优先级一样去处理

// 比如把251分成11份每份25 最后第11份只有1个
// 然后把它扔掉 直接补一个25 变成11个25份
// 最后结果就是275个
// 再比如把255分成11份每份25 最后第11份只有5个
// 然后把它扔掉 直接补一个25 变成11个25份
// 最后结果还是275个

function ceiling(num, precision) {
  // 当react中执行了多个setState时
  // 每个setState之间的差距可能是非常小的
  // 如果不提供调整的话 最后expirationTime的结果会不一样
  // 结果不一样就意味着优先级不一样
  // 就可能会导致任务更新执行多次 从而性能下降

  // num 表示本次更新最多只能运行到第 num 个单元
  // precision 表示相差在 precision 单元之内的更新要被抹平

  // 举个例子
  // 第一次更新最多只能运行到第 155 个单元(num)
  // 第二次更新最多只能运行到第 155.3 个单元(num)
  // 希望相差在2个单元内的更新的优先级是一样的(precision)
  // 所以第一次更新就是 (155 / 2 | 0 + 1) * 2 = 156
  // 然后第二次更新就是 (155.3 / 2 | 0 + 1) * 2 = 156
  // 触发时间特别相近的两次更新最终能执行到的单元都是156
  // 这样就抹平了特别近的两次更新的优先级的差异
  // 要不两次优先级差别特别大的话 那就可能会多次执行更新操作
  return (((num / precision) | 0) + 1) * precision
}

// /*
//   低优先级: 将25ms内的连续两次更新的优先级当成一个
//     1073741822 - { [ ( 1073741822 - current + 500 ) / 25 ] | 0 } * 25
//   高优先级: 将10ms内的连续两次更新的优先级当成一个
//     1073741822 - { [ ( 1073741822 - current + 50 ) / 10 ] | 0 } * 10
// */

// 1073741822 - ((( (1073741822 - currentTime + expirationInMs / UNIT_SIZE) / (bucketSizeMs / UNIT_SIZE)) | 0) + 1) * (bucketSizeMs / UNIT_SIZE)
// currentTime代表react最多还能再处理多少单元
function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) {
  return (
    MAGIC_NUMBER_OFFSET -
    ceiling(
      // expirationInMs / UNIT_SIZE 意思就是把本次render阶段的时间换算成react中的单元(unit)
      // MAGIC_NUMBER_OFFSET - currentTime 表示用react最大能处理的单元数 减去剩下还能再处理的单元数
      // 得到的结果代表当前已经花费的单元数 之后再加上本次render阶段要用掉的单元数
      // 所以MAGIC_NUMBER_OFFSET - currentTime + expirationInMs / UNIT_SIZE的意思就是
      // 算出最终本轮更新最终能执行到多少单元数

      // ceiling就是取一下整 将时间特别接近的两次更新的时间优先级变成一样的

      // 然后外层再用MAGIC_NUMBER_OFFSET减去ceiling得到的东西
      // 所以最后的意思
      // 我认为就是: 执行完本次更新 最少还能剩下多少单元

      // 举个例子
      // 比如说react能处理100个单元(MAGIC_NUMBER_OFFSET)
      // 程序到现在已经花费了10个单元了
      // 所以现在还剩90个单元能让我用(currentTime)
      // 然后每次更新我只让你最多能用掉5个单元(expirationInMs / UNIT_SIZE)
      // 所以用100 - 90 + 5 = 15
      // 所以得到的结果的意思就是
      // "现在程序已经运行了10个单元了 你这次更新最多只能运行到第15个单元 15个单元内 可以随便中断 超过15单元后 就不能中断了"
      // 之后取一下整 把相差特别近的两次更新之间差异给抹平
      // 再用 100 - 15 = 85
      // 结果的意思就是 执行完本次更新后 可能还剩下85个单元能干活
      // 然后最终得到的数字越大 说明本次的更新被触发的时间越靠前
      // 就越应该被先执行 也就是优先级更大
      
      // 以上只是个人理解
      MAGIC_NUMBER_OFFSET - currentTime + expirationInMs / UNIT_SIZE,
      // bucketSizeMs代表相差在xx毫秒内
      // 所以 bucketSizeMs / UNIT_SIZE 意思就是相差在 xx 个单元之内
      bucketSizeMs / UNIT_SIZE
    )
  )
}

// LOW_PRIORITY_EXPIRATION是说低优先级的更新的render阶段最多只给你5000ms的时间
export const LOW_PRIORITY_EXPIRATION = 5000
export const LOW_PRIORITY_BATCH_SIZE = 250

export function computeAsyncExpiration(currentTime) {
  return computeExpirationBucket(
    currentTime,
    LOW_PRIORITY_EXPIRATION,
    LOW_PRIORITY_BATCH_SIZE
  )
}

// HIGH_PRIORITY_EXPIRATION 是说本次更新的render阶段 最多只给你500ms的时间
export const HIGH_PRIORITY_EXPIRATION = 500 // react中生产环境变成150
export const HIGH_PRIORITY_BATCH_SIZE = 100

// currentTime: 1073741822 - ((当前花费时间 / 10) | 0)
// 1073741822 - (当前花费时间 / 10)
// 这个东西返回结果就相当于             dev环境50  ↓  prod环境15
// 1073741822 - (((1073741822 - currentTime + 50) / 10 | 0) + 1) * 10
// 这个公式的意思跟上面async的意思基本一样
// 就是差距在10以内的两个时间 有可能最后截止时间是一样的
export function computeInteractiveExpiration(currentTime) {
  return computeExpirationBucket(
    currentTime,
    HIGH_PRIORITY_EXPIRATION,
    HIGH_PRIORITY_BATCH_SIZE
  )
}