前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React源码解析之ExpirationTime

React源码解析之ExpirationTime

作者头像
进击的小进进
发布2019-09-05 17:26:20
9260
发布2019-09-05 17:26:20
举报

一、ExpirationTime的作用React中,为防止某个update因为优先级的原因一直被打断而未能执行。React会设置一个ExpirationTime,当时间到了ExpirationTime的时候,如果某个update还未执行的话,React将会强制执行该update,这就是ExpirationTime的作用。

二、位置 在React源码解析之ReactDOM.render()中,已经讲解了updateContainer()

export function updateContainer(
  element: ReactNodeList,
  container: OpaqueRoot,
  parentComponent: ?React$Component<any, any>,
  callback: ?Function,
): ExpirationTime {
   ...
   //计算过期时间,这是React优先级更新非常重要的点
  const expirationTime = computeExpirationForFiber(
    currentTime,
    current,
    suspenseConfig,
  );
   ...
}

computeExpirationForFiber

//为fiber对象计算expirationTime
export function computeExpirationForFiber(
  currentTime: ExpirationTime,
  fiber: Fiber,
  suspenseConfig: null | SuspenseConfig,
): ExpirationTime {
  ...
  // Compute an expiration time based on the Scheduler priority.
    switch (priorityLevel) {
      case ImmediatePriority:
        expirationTime = Sync;
        break;
      case UserBlockingPriority:
        // TODO: Rename this to computeUserBlockingExpiration
        //一个是计算交互事件(如点击)的过期时间
        expirationTime = computeInteractiveExpiration(currentTime);
        break;
      case NormalPriority:
      case LowPriority: // TODO: Handle LowPriority
        // TODO: Rename this to... something better.
        //一个是计算异步更新的过期时间
        expirationTime = computeAsyncExpiration(currentTime);
        break;
      case IdlePriority:
        expirationTime = Never;
        break;
      default:
        invariant(false, 'Expected a valid priority level');
    }
  ...
}

我们可以看到有两个计算expirationTime的方法,分别为computeInteractiveExpiration()computeAsyncExpiration()

先看下computeAsyncExpiration()

三、computeAsyncExpiration() 作用: 返回低优先级(普通异步更新)的expirationTime(过期时间)

源码:

//低权限的过期时间
export const LOW_PRIORITY_EXPIRATION = 5000;
export const LOW_PRIORITY_BATCH_SIZE = 250;
//普通的异步的expirationTime
export function computeAsyncExpiration(
  currentTime: ExpirationTime,
): ExpirationTime {
  return computeExpirationBucket(
    currentTime,
    //5000
    LOW_PRIORITY_EXPIRATION,
    //250
    LOW_PRIORITY_BATCH_SIZE,
  );
}

解析: currentTime先按下不表,LOW_PRIORITY_EXPIRATION5000LOW_PRIORITY_BATCH_SIZE250,注意它的名字LOW_PRIORITY_BATCH_SIZE,下面会提到

四、computeExpirationBucket() 作用: 计算过期时间

源码:

//1073741823
export const Sync = MAX_SIGNED_31_BIT_INT;
//1073741822
export const Batched = Sync - 1;

const UNIT_SIZE = 10;
//1073741821
const MAGIC_NUMBER_OFFSET = Batched - 1;

function ceiling(num: number, precision: number): number {
  return (((num / precision) | 0) + 1) * precision;
}

//计算过期时间
function computeExpirationBucket(
  currentTime,
  expirationInMs,
  bucketSizeMs,
): ExpirationTime {
  return (
    //1073741821
    MAGIC_NUMBER_OFFSET -
    ceiling(
      //   1073741821-currentTime+(high 150 或者 low 5000  /10)  ,
      MAGIC_NUMBER_OFFSET - currentTime + expirationInMs / UNIT_SIZE,
      //(high 100 或者 low 250  /10 )
      bucketSizeMs / UNIT_SIZE,
    )
  );
}

解析: (1)MAX_SIGNED_31_BIT_INT

// Max 31 bit integer. The max integer size in V8 for 32-bit systems.
// Math.pow(2, 30) - 1
// 0b111111111111111111111111111111
//整型最大数值,是V8中针对32位系统所设置的最大值
export default 1073741823;

(2)| 0的意思是取整

console.log(16/3 |0) //5

(3)根据computeExpirationBucket()里面的公式,计算下异步更新的过期时间:

   //low 情况
  1073741821-ceiling(1073741821-currentTime+500,25)

  1073741821-((((1073741821-currentTime+500) / 25) | 0) + 1) * 25

  1073741821-((1073741821/25-currentTime/25+20 | 0) + 1) * 25

  1073741821-((1073741821/25-currentTime/25+20*25/25 | 0) + 1) * 25

  1073741821-((1073741821-currentTime+500)/25 | 0)*25 - 25

  1073741796-((1073741821-currentTime+500)/25 | 0)*25

  1073741796-((1073742321-currentTime)/25 | 0)*25
  //======我们直接取最后四位来探索规律===================
  1796-((2321-currentTime)/25 | 0)*25
  //假设 currentTime 是 2000
  1796-(2321- 2000 /25 | 0)*25 //1796-300
  //currentTime是2010
  1796-(311/25 | 0)*25 //1796-300
  //currentTime是2024
  1796-(311/25 | 0)*25 //1796-275
  //currentTime是2025
  1796-(311/25 | 0)*25 //1796-275

可以看到,低优先的过期时间间隔25ms 同理,高优先级的过期时间间隔10ms

  //high 情况
  1073741821-ceiling(1073741821-currentTime+15,10)

也就是说,React低优先级updateexpirationTime间隔是25msReact让两个相近(25ms内)的update得到相同的expirationTime,目的就是让这两个update自动合并成一个Update,从而达到批量更新的目的,就像LOW_PRIORITY_BATCH_SIZE的名字一样,自动合并批量更新。

想象一下,开发者不停地使用setState()更新ReactApp,如果不把相近的update合并的话,会严重影响性能,就像提到的doubleBuffer一样,React为提高性能,考虑得非常全面!


本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 webchen 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档