React的fiber調(diào)度和expirationTime有著密不可分的聯(lián)系,expirationTime決定著每個(gè)任務(wù)的優(yōu)先級(jí)。一個(gè)expirationTime就是一個(gè)10ms的時(shí)間單位。
源碼不長(zhǎng),我們先看源碼,然后逐一分析每個(gè)函數(shù)。
import MAX_SIGNED_31_BIT_INT from './maxSigned31BitInt';
import {
ImmediatePriority,
UserBlockingPriority,
NormalPriority,
IdlePriority,
} from './SchedulerWithReactIntegration';
export const NoWork = 0;
export const Never = 1;
export const Sync = MAX_SIGNED_31_BIT_INT;
export const Batched = Sync - 1;
const UNIT_SIZE = 10;
const MAGIC_NUMBER_OFFSET = Batched - 1;
// 1 unit of expiration time represents 10ms.
export function msToExpirationTime(ms) {
// Always add an offset so that we don't clash with the magic number for NoWork.
return MAGIC_NUMBER_OFFSET - ((ms / UNIT_SIZE) | 0);
}
export function expirationTimeToMs(expirationTime) {
return (MAGIC_NUMBER_OFFSET - expirationTime) * UNIT_SIZE;
}
function ceiling(num, precision) {
return (((num / precision) | 0) + 1) * precision;
}
function computeExpirationBucket(
currentTime,
expirationInMs,
bucketSizeMs,
) {
return (
MAGIC_NUMBER_OFFSET -
ceiling(
MAGIC_NUMBER_OFFSET - currentTime + expirationInMs / UNIT_SIZE,
bucketSizeMs / UNIT_SIZE,
)
);
}
// TODO: This corresponds to Scheduler's NormalPriority, not LowPriority. Update
// the names to reflect.
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,
);
}
export function computeSuspenseExpiration(
currentTime,
timeoutMs,
) {
// TODO: Should we warn if timeoutMs is lower than the normal pri expiration time?
return computeExpirationBucket(
currentTime,
timeoutMs,
LOW_PRIORITY_BATCH_SIZE,
);
}
// We intentionally set a higher expiration time for interactive updates in
// dev than in production.
//
// If the main thread is being blocked so long that you hit the expiration,
// it's a problem that could be solved with better scheduling.
//
// People will be more likely to notice this and fix it with the long
// expiration time in development.
//
// In production we opt for better UX at the risk of masking scheduling
// problems, by expiring fast.
export const HIGH_PRIORITY_EXPIRATION = __DEV__ ? 500 : 150;
export const HIGH_PRIORITY_BATCH_SIZE = 100;
export function computeInteractiveExpiration(currentTime) {
return computeExpirationBucket(
currentTime,
HIGH_PRIORITY_EXPIRATION,
HIGH_PRIORITY_BATCH_SIZE,
);
}
export function inferPriorityFromExpirationTime(
currentTime,
expirationTime,
) {
if (expirationTime === Sync) {
return ImmediatePriority;
}
if (expirationTime === Never) {
return IdlePriority;
}
const msUntil =
expirationTimeToMs(expirationTime) - expirationTimeToMs(currentTime);
if (msUntil <= 0) {
return ImmediatePriority;
}
if (msUntil <= HIGH_PRIORITY_EXPIRATION + HIGH_PRIORITY_BATCH_SIZE) {
return UserBlockingPriority;
}
if (msUntil <= LOW_PRIORITY_EXPIRATION + LOW_PRIORITY_BATCH_SIZE) {
return NormalPriority;
}
// TODO: Handle LowPriority
// Assume anything lower has idle priority
return IdlePriority;
}
在16.8.6版本的React中,expirationTime采用了減法策略。pr: Flip expiration times。所以現(xiàn)在的expirationTime越大,優(yōu)先級(jí)越高。
-
msToExpirationTime和msToExpirationTime從ms時(shí)間戳到expirationTime的轉(zhuǎn)換 -
ceiling以某個(gè)精度范圍向上取整。 -
computeExpirationBucket為了計(jì)算在某個(gè)bucket精度內(nèi)的expirationTime,輸入不同的expirationInMs,bucketSizeMs參數(shù)可以定義不同優(yōu)先級(jí)的expirationTime -
computeAsyncExpiration是一個(gè)計(jì)算可以中斷的任務(wù)的低優(yōu)先級(jí)expirationTime的函數(shù),內(nèi)部調(diào)用了computeExpirationBucket。 -
computeInteractiveExpiration是一個(gè)計(jì)算不可以中斷的任務(wù)的高優(yōu)先級(jí)expirationTime的函數(shù),內(nèi)部調(diào)用了computeExpirationBucket。 -
inferPriorityFromExpirationTime:通過(guò)把expirationTime和currentTime化為ms單位,并計(jì)算他們的差值,通過(guò)判斷差值落在哪個(gè)區(qū)間去判斷屬于哪個(gè)優(yōu)先級(jí)。主要分為四個(gè)優(yōu)先級(jí):ImmediatePriority: <=0;UserBlockingPriority: 0 ~ (HIGH_PRIORITY_EXPIRATION + HIGH_PRIORITY_BATCH_SIZE);NormalPriority: (HIGH_PRIORITY_EXPIRATION + HIGH_PRIORITY_BATCH_SIZE) ~ (LOW_PRIORITY_EXPIRATION + LOW_PRIORITY_BATCH_SIZE);
其他情況就是IdlePriority