ReactDOM.render
当中,它计算 expirationTime 的地方
updateContainer
函数中,通过 computeExpirationForFiber
方法来计算一个过期时间const current = container.current; // 参数2
const currentTime = requestCurrentTime(); // 参数1 我们可以近似理解为: 当前时间到js加载完成的时间的时间差值即可
const expirationTime = computeExpirationForFiber(currentTime, current);
requestCurrentTime
这个函数,来自于 ReactFiberScheduler.js 中function requestCurrentTime() {
// 这里,我把官方注释移除
// 这里表示 已经进入到 渲染阶段 了,在 ReactDOM.render 中这里不会匹配,会跳过
// 在一次render中,如果我有一个新的任务进来了,要计算 expirationTime 发现现在处于渲染阶段,这时直接返回上次 render 开始的时间,再去计算 expirationTime
// 好处是 前后两次计算出来的 expirationTime 是一样的,让这个任务提前进行调度
if (isRendering) {
// We're already rendering. Return the most recently read time.
return currentSchedulerTime;
}
// Check if there's pending work.
findHighestPriorityRoot();
// 刚初始化的时候,这个条件是成立的
if (
nextFlushedExpirationTime === NoWork ||
nextFlushedExpirationTime === Never
) {
// If there's no pending work, or if the pending work is offscreen, we can
// read the current time without risk of tearing.
recomputeCurrentRendererTime();
currentSchedulerTime = currentRendererTime; // 两个常量划等号
return currentSchedulerTime;
}
// 这里,我把官方注释移除
return currentSchedulerTime;
}
findHighestPriorityRoot
方法涉及到从调度队列中找到权限最高的 Root
recomputeCurrentRendererTime
每一次做计算都是从当前到js加载完成后的时间间隔,再经过一些计算得到的值,function recomputeCurrentRendererTime() {
const currentTimeMs = now() - originalStartTimeMs; // 当前时间 - react buddle加载完成之后初始的时间,也就是从js加载完成到现在的时间间隔
currentRendererTime = msToExpirationTime(currentTimeMs); // 计算出 currentRendererTime
}
// ReactFiberExpirationTime.js 这个函数得到一个时间戳
export function msToExpirationTime(ms: number): ExpirationTime {
// Always add an offset so that we don't clash with the magic number for NoWork.
return ((ms / UNIT_SIZE) | 0) + MAGIC_NUMBER_OFFSET; // UNIT_SIZE 是固定的 10, | 0 是取整的意思, MAGIC_NUMBER_OFFSET 是固定的 2
}
expirationTime
的计算函数 computeExpirationForFiber
有一个计算公式function ceiling(num: number, precision: number): number {
return (((num / precision) | 0) + 1) * precision;
}
function computeExpirationBucket(
currentTime,
expirationInMs,
bucketSizeMs,
): ExpirationTime {
return (
MAGIC_NUMBER_OFFSET +
ceiling(
currentTime - MAGIC_NUMBER_OFFSET + expirationInMs / UNIT_SIZE,
bucketSizeMs / UNIT_SIZE,
)
);
}
// 低权限计算
export function computeAsyncExpiration(
currentTime: ExpirationTime,
): ExpirationTime {
return computeExpirationBucket(
currentTime,
LOW_PRIORITY_EXPIRATION, // 5000
LOW_PRIORITY_BATCH_SIZE, // 250
);
}
// 高权限计算
export function computeInteractiveExpiration(currentTime: ExpirationTime) {
return computeExpirationBucket(
currentTime,
HIGH_PRIORITY_EXPIRATION, // 500/150 前 DEV, 后 PROD
HIGH_PRIORITY_BATCH_SIZE, // 100
);
}
computeExpirationBucket
方法来计算的((((currentTime - 2 + 5000 / 10) / 25) | 0 ) + 1) * 25
expirationTime
是以 bucketSize / UNIT_SIZE
这个单元向上叠加的expirationTime
的差距是 单元值的 倍数LOW_PRIORITY_BATCH_SIZE
是 以 25 为单元向上加的, 若前后差距在25以内,计算出来的差距都是一样的HIGH_PRIORITY_BATCH_SIZE
是 以 10 为单元向上加的,同上expirationTime
时setState
, 即便前后调用差距很小,但从毫秒级别看,还是有差距的setState
和 下一个 setState
之间差距特别小,算出来的 expirationTime
结果不一样expirationTime
结果一样,则它们优先级也是一样的,而不需要进行区分| 0
表示 去余取整expirationTime
的作用还要结合后期更新的流程来看expirationTime
是一个和业务无关的比较纯粹的计算过程问题,没有任何副作用