React 分析器计时器
一、作用
二、导出常量/变量
1. 更新状态
// 定期更新
export const REGULAR_UPDATE: UpdateType = 0;
// 生成更新
export const SPAWNED_UPDATE: UpdateType = 1;
// 已 ping 更新
export const PINGED_UPDATE: UpdateType = 2;
2. 时间
// 渲染开始时间
export let renderStartTime: number = -0;
// 提交开始时间
export let commitStartTime: number = -0;
// 提交结束时间
export let commitEndTime: number = -0;
// 提交中的错误
export let commitErrors: null | Array<CapturedValue<mixed>> = null;
// 分析器开始时间
export let profilerStartTime: number = -1.1;
// 分析器效果持续时间
export let profilerEffectDuration: number = -0;
// 组件效果持续时间
export let componentEffectDuration: number = -0;
// 组件效果开始时间
export let componentEffectStartTime: number = -1.1;
// 组件效果结束时间
export let componentEffectEndTime: number = -1.1;
// 组件效果错误
export let componentEffectErrors: null | Array<CapturedValue<mixed>> = null;
// 组件效果生成更新
export let componentEffectSpawnedUpdate: boolean = false;
// 阻塞占用时间
export let blockingClampTime: number = -0;
// First sync setState scheduled.
// 首次同步已调度 setState。
// 阻塞更新时间
export let blockingUpdateTime: number = -1.1;
// First sync setState's stack trace.
// 首先同步 setState 的堆栈跟踪。
// 阻塞更新任务
export let blockingUpdateTask: null | ConsoleTask = null;
// 阻塞更新类型
export let blockingUpdateType: UpdateType = 0;
// The name of the method that caused first sync update.
// 导致第一次同步更新的方法名称。
// 阻塞更新方法名称
export let blockingUpdateMethodName: null | string = null;
// The name of the component where first sync update happened.
// 第一次同步更新发生的组件名称。
// 阻塞更新组件名称
export let blockingUpdateComponentName: null | string = null;
// Event timeStamp of the first setState.
// 第一次 setState 的事件时间戳。
// 阻塞事件时间
export let blockingEventTime: number = -1.1;
// 阻塞事件类型
export let blockingEventType: null | string = null;
// Event type of the first setState.
// 第一次 setState 的事件类型。
// 阻止事件重复时间
export let blockingEventRepeatTime: number = -1.1;
// 阻塞挂起时间
export let blockingSuspendedTime: number = -1.1;
// 手势占用时间
export let gestureClampTime: number = -0;
// First setOptimistic scheduled inside startGestureTransition.
// 首先在 startGestureTransition 内部调度 setOptimistic。
// 手势更新时间
export let gestureUpdateTime: number = -1.1;
// First sync setState's stack trace.
// 首先同步 setState 的堆栈跟踪。
// 手势更新任务
export let gestureUpdateTask: null | ConsoleTask = null;
// 手势更新类型
export let gestureUpdateType: UpdateType = 0;
// The name of the method that caused first gesture update.
// 导致第一次手势更新的方法名称。
// 手势更新方法名称
export let gestureUpdateMethodName: null | string = null;
// The name of the component where first gesture update happened.
// 第一次手势更新发生的组件名称。
// 手势更新组件名称
export let gestureUpdateComponentName: null | string = null;
// Event timeStamp of the first setState.
// 第一次 setState 的事件时间戳。
// 手势事件时间
export let gestureEventTime: number = -1.1;
// Event type of the first setState.
// 第一次 setState 的事件类型。
// 手势事件类型
export let gestureEventType: null | string = null;
// 手势事件重复时间
export let gestureEventRepeatTime: number = -1.1;
// 手势暂停时间
export let gestureSuspendedTime: number = -1.1;
// TODO: This should really be one per Transition lane.
// 待办:这实际上应该每个过渡 Lane 一个。
// 过渡占用时间
export let transitionClampTime: number = -0;
// First startTransition call before setState.
// 在 setState 之前第一次调用 startTransition。
// 过渡开始时间
export let transitionStartTime: number = -1.1;
// First transition setState scheduled.
// First transition setState scheduled.
// 过渡更新时间
export let transitionUpdateTime: number = -1.1;
// 过渡更新类型
export let transitionUpdateType: UpdateType = 0;
// First transition setState's stack trace.
// 首先是 transition setState 的堆栈跟踪。
// 过渡更新任务
export let transitionUpdateTask: null | ConsoleTask = null;
// The name of the method that caused first transition update.
// 导致第一次转换更新的方法名称。
// 过渡更新方法名称
export let transitionUpdateMethodName: null | string = null;
// The name of the component where first transition update happened.
// 第一次过渡更新发生的组件名称。
// 过渡更新组件名称
export let transitionUpdateComponentName: null | string = null;
// Event timeStamp of the first transition.
// 第一次转换的事件时间戳。
// 过渡事件时间
export let transitionEventTime: number = -1.1;
// Event type of the first transition.
// 第一次转换的事件类型。
// 过渡事件类型
export let transitionEventType: null | string = null;
// 过渡事件重复时间
export let transitionEventRepeatTime: number = -1.1;
// 过渡暂停时间
export let transitionSuspendedTime: number = -1.1;
// 重试限制时间
export let retryClampTime: number = -0;
// 空闲占用时间
export let idleClampTime: number = -0;
// 动画 Lanes
export let animatingLanes: Lanes = NoLanes;
// First ViewTransition applying an Animation.
// 首次 ViewTransition 使用动画。
// 动画任务
export let animatingTask: null | ConsoleTask = null;
// 暂停原因
export let yieldReason: SuspendedReason = 0 as any;
// The time when we yielded to the event loop
// 我们让出给事件循环的时间
// 暂停开始时间
export let yieldStartTime: number = -1.1;
三、开始产出计时器
信息
enableProfilerTimer和enableComponentPerformanceTrack在 shared 中now()在 Scheduler 中实现
export function startYieldTimer(reason: SuspendedReason) {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return;
}
yieldStartTime = now();
yieldReason = reason;
}
四、 按 Lane 启动更新计时器
信息
isGestureRender()在 ReactFiberLane#isGestureRender 中实现now()在 Scheduler 中实现getComponentNameFromFiber()在 getComponentNameFromFiber 中实现resolveEventTimeStamp()、resolveEventType()由渲染的平台进行实现isBlockingLane()由 ReactFiberLane#isBlockingLane 中实现isAlreadyRendering()、isAlreadyRendering()由 ReactFiverWorkLoop 中实现
export function startUpdateTimerByLane(
lane: Lane,
method: string,
fiber: Fiber | null,
): void {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return;
}
if (isGestureRender(lane)) {
if (gestureUpdateTime < 0) {
gestureUpdateTime = now();
gestureUpdateTask = createTask(method);
gestureUpdateMethodName = method;
if (__DEV__ && fiber != null) {
gestureUpdateComponentName = getComponentNameFromFiber(fiber);
}
const newEventTime = resolveEventTimeStamp();
const newEventType = resolveEventType();
if (
newEventTime !== gestureEventRepeatTime ||
newEventType !== gestureEventType
) {
gestureEventRepeatTime = -1.1;
}
gestureEventTime = newEventTime;
gestureEventType = newEventType;
}
} else if (isBlockingLane(lane)) {
if (blockingUpdateTime < 0) {
blockingUpdateTime = now();
blockingUpdateTask = createTask(method);
blockingUpdateMethodName = method;
if (__DEV__ && fiber != null) {
blockingUpdateComponentName = getComponentNameFromFiber(fiber);
}
if (isAlreadyRendering()) {
componentEffectSpawnedUpdate = true;
blockingUpdateType = SPAWNED_UPDATE;
}
const newEventTime = resolveEventTimeStamp();
const newEventType = resolveEventType();
if (
newEventTime !== blockingEventRepeatTime ||
newEventType !== blockingEventType
) {
blockingEventRepeatTime = -1.1;
} else if (newEventType !== null) {
// If this is a second update in the same event, we treat it as a spawned update.
// This might be a microtask spawned from useEffect, multiple flushSync or
// a setState in a microtask spawned after the first setState. Regardless it's bad.
//
// 如果这是同一事件中的第二次更新,我们将其视为派生更新。
// 这可能是由 useEffect 生成的微任务、多个 flushSync,或者在第一次 setState 之后生成
// 的微任务中的 setState。无论如何,这都是不好的。
blockingUpdateType = SPAWNED_UPDATE;
}
blockingEventTime = newEventTime;
blockingEventType = newEventType;
}
} else if (isTransitionLane(lane)) {
if (transitionUpdateTime < 0) {
transitionUpdateTime = now();
transitionUpdateTask = createTask(method);
transitionUpdateMethodName = method;
if (__DEV__ && fiber != null) {
transitionUpdateComponentName = getComponentNameFromFiber(fiber);
}
if (transitionStartTime < 0) {
const newEventTime = resolveEventTimeStamp();
const newEventType = resolveEventType();
if (
newEventTime !== transitionEventRepeatTime ||
newEventType !== transitionEventType
) {
transitionEventRepeatTime = -1.1;
}
transitionEventTime = newEventTime;
transitionEventType = newEventType;
}
}
}
}
五、 启动主机操作计时器
信息
now()在 Scheduler 中实现resolveEventTimeStamp()、resolveEventType()由渲染的平台进行实现isAlreadyRendering()、isAlreadyRendering()由 ReactFiverWorkLoop 中实现
export function startHostActionTimer(fiber: Fiber): void {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return;
}
// This schedules an update on both the blocking lane for the pending state and on the
// transition lane for the action update. Using the debug task from the host fiber.
//
// 这将在待处理状态的阻塞通道和操作更新的过渡通道上调度更新。使用来自主纤维的调试任务。
if (blockingUpdateTime < 0) {
blockingUpdateTime = now();
blockingUpdateTask =
__DEV__ && fiber._debugTask != null ? fiber._debugTask : null;
if (isAlreadyRendering()) {
blockingUpdateType = SPAWNED_UPDATE;
}
const newEventTime = resolveEventTimeStamp();
const newEventType = resolveEventType();
if (
newEventTime !== blockingEventRepeatTime ||
newEventType !== blockingEventType
) {
blockingEventRepeatTime = -1.1;
} else if (newEventType !== null) {
// If this is a second update in the same event, we treat it as a spawned update.
// This might be a microtask spawned from useEffect, multiple flushSync or
// a setState in a microtask spawned after the first setState. Regardless it's bad.
//
// 如果这是同一事件中的第二次更新,我们将其视为派生更新。
// 这可能是由 useEffect 生成的微任务、多个 flushSync,或者在第一次 setState 之后生成
// 的微任务中的 setState。无论如何,这都是不好的。
blockingUpdateType = SPAWNED_UPDATE;
}
blockingEventTime = newEventTime;
blockingEventType = newEventType;
}
if (transitionUpdateTime < 0) {
transitionUpdateTime = now();
transitionUpdateTask =
__DEV__ && fiber._debugTask != null ? fiber._debugTask : null;
if (transitionStartTime < 0) {
const newEventTime = resolveEventTimeStamp();
const newEventType = resolveEventType();
if (
newEventTime !== transitionEventRepeatTime ||
newEventType !== transitionEventType
) {
transitionEventRepeatTime = -1.1;
}
transitionEventTime = newEventTime;
transitionEventType = newEventType;
}
}
}
六、 按 Lanes 启动 Ping 定时器
信息
isGestureRender()在 ReactFiberLane#isGestureRender 中实现now()在 Scheduler 中实现includesBlockingLane()在 ReactFiberLane#includesBlockingLane 中实现includesTransitionLane()在 ReactFiberLane#includesTransitionLane 中实现
export function startPingTimerByLanes(lanes: Lanes): void {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return;
}
// Mark the update time and clamp anything before it because we don't want
// to show the event time for pings but we also don't want to clear it
// because we still need to track if this was a repeat.
//
// 标记更新时间并限制之前的内容,因为我们不想显示 pings 的事件时间,但也不想清除它
// 因为我们仍然需要跟踪这是否是重复事件。
if (isGestureRender(lanes)) {
if (gestureUpdateTime < 0) {
gestureClampTime = gestureUpdateTime = now();
gestureUpdateTask = createTask('Promise Resolved');
gestureUpdateType = PINGED_UPDATE;
}
} else if (includesBlockingLane(lanes)) {
if (blockingUpdateTime < 0) {
blockingClampTime = blockingUpdateTime = now();
blockingUpdateTask = createTask('Promise Resolved');
blockingUpdateType = PINGED_UPDATE;
}
} else if (includesTransitionLane(lanes)) {
if (transitionUpdateTime < 0) {
transitionClampTime = transitionUpdateTime = now();
transitionUpdateTask = createTask('Promise Resolved');
transitionUpdateType = PINGED_UPDATE;
}
}
}
七、跟踪暂停时间
信息
isGestureRender()在 ReactFiberLane#isGestureRender 中实现now()在 Scheduler 中实现includesBlockingLane()在 ReactFiberLane#includesBlockingLane 中实现includesTransitionLane()在 ReactFiberLane#includesTransitionLane 中实现
export function trackSuspendedTime(lanes: Lanes, renderEndTime: number) {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return;
}
if (isGestureRender(lanes)) {
gestureSuspendedTime = renderEndTime;
} else if (includesBlockingLane(lanes)) {
blockingSuspendedTime = renderEndTime;
} else if (includesTransitionLane(lanes)) {
transitionSuspendedTime = renderEndTime;
}
}
八、清除阻塞计时器
信息
now()在 Scheduler 中实现
export function clearBlockingTimers(): void {
blockingUpdateTime = -1.1;
blockingUpdateType = 0;
blockingUpdateMethodName = null;
blockingUpdateComponentName = null;
blockingSuspendedTime = -1.1;
blockingEventRepeatTime = blockingEventTime;
blockingEventTime = -1.1;
blockingClampTime = now();
}
九、 过渡工作
1. 启动异步过渡计时器
信息
now()在 Scheduler 中实现resolveEventTimeStamp()、resolveEventType()由渲染的平台进行实现
export function startAsyncTransitionTimer(): void {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return;
}
if (transitionStartTime < 0 && transitionUpdateTime < 0) {
transitionStartTime = now();
const newEventTime = resolveEventTimeStamp();
const newEventType = resolveEventType();
if (
newEventTime !== transitionEventRepeatTime ||
newEventType !== transitionEventType
) {
transitionEventRepeatTime = -1.1;
}
transitionEventTime = newEventTime;
transitionEventType = newEventType;
}
}
2. 已安排过渡工作
export function hasScheduledTransitionWork(): boolean {
// If we have setState on a transition or scheduled useActionState update.
// 如果我们在一个过渡中使用了 setState 或安排了 useActionState 更新。
return transitionUpdateTime > -1;
}
3. 清除异步过渡定时器
export function clearAsyncTransitionTimer(): void {
transitionStartTime = -1.1;
}
4. 清除过渡计时器
信息
now()在 Scheduler 中实现
export function clearTransitionTimers(): void {
transitionStartTime = -1.1;
transitionUpdateTime = -1.1;
transitionUpdateType = 0;
transitionSuspendedTime = -1.1;
transitionEventRepeatTime = transitionEventTime;
transitionEventTime = -1.1;
transitionClampTime = now();
}
十、手势
1. 已安排手势过渡工作
export function hasScheduledGestureTransitionWork(): boolean {
// If we have call setOptimistic on a gesture
// 如果我们在一个手势上调用 setOptimistic
return gestureUpdateTime > -1;
}
2. 清除手势计时器
信息
now()在 Scheduler 中实现
export function clearGestureTimers(): void {
gestureUpdateTime = -1.1;
gestureUpdateType = 0;
gestureSuspendedTime = -1.1;
gestureEventRepeatTime = gestureEventTime;
gestureEventTime = -1.1;
gestureClampTime = now();
}
3. 清除手势更新
export function clearGestureUpdates(): void {
// Same as clearGestureTimers but doesn't reset the clamp time because we didn't
// actually emit a render.
// 与 clearGestureTimers 相同,但不重置夹紧时间,因为我们实际上并未触发渲染。
gestureUpdateTime = -1.1;
gestureUpdateType = 0;
gestureSuspendedTime = -1.1;
gestureEventRepeatTime = gestureEventTime;
gestureEventTime = -1.1;
}
十一、占用计时器
1. 占用阻塞计时器
export function clampBlockingTimers(finalTime: number): void {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return;
}
// If we had new updates come in while we were still rendering or committing, we don't want
// those update times to create overlapping tracks in the performance timeline so we clamp
// them to the end of the commit phase.
//
// 如果在我们仍在渲染或提交时有新的更新到来,我们不希望这些更新的时间在性能时间轴上造成重叠的轨迹,
// 因此我们将它们限制到提交阶段的末尾。
blockingClampTime = finalTime;
}
2. 占用手势计时器
export function clampGestureTimers(finalTime: number): void {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return;
}
// If we had new updates come in while we were still rendering or committing, we don't want
// those update times to create overlapping tracks in the performance timeline so we clamp
// them to the end of the commit phase.
//
// 如果在我们仍在渲染或提交时有新的更新到来,我们不希望这些更新的时间在性能时间轴上造成重叠的轨迹,
// 因此我们将它们限制到提交阶段的末尾。
gestureClampTime = finalTime;
}
3. 占用过渡计时器
export function clampTransitionTimers(finalTime: number): void {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return;
}
// If we had new updates come in while we were still rendering or committing, we don't want
// those update times to create overlapping tracks in the performance timeline so we clamp
// them to the end of the commit phase.
//
// 如果在我们仍在渲染或提交时有新的更新到来,我们不希望这些更新的时间在性能时间轴上造成重叠的轨迹,
// 因此我们将它们限制到提交阶段的末尾。
transitionClampTime = finalTime;
}
4. 占用重试计时器
export function clampRetryTimers(finalTime: number): void {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return;
}
retryClampTime = finalTime;
}
5. 占用空间计时器
export function clampIdleTimers(finalTime: number): void {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return;
}
idleClampTime = finalTime;
}
十二、嵌套效果
1. 添加嵌套效果持续时间
export function pushNestedEffectDurations(): number {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return 0;
}
const prevEffectDuration = profilerEffectDuration;
profilerEffectDuration = 0; // Reset counter.
return prevEffectDuration;
}
2. 弹出嵌套效果持续时间
export function popNestedEffectDurations(prevEffectDuration: number): number {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return 0;
}
const elapsedTime = profilerEffectDuration;
profilerEffectDuration = prevEffectDuration;
return elapsedTime;
}
3. 冒泡嵌套效果
// Like pop but it also adds the current elapsed time to the parent scope.
// 类似 pop,但它还会将当前经过的时间添加到父作用域。
export function bubbleNestedEffectDurations(
prevEffectDuration: number,
): number {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return 0;
}
const elapsedTime = profilerEffectDuration;
profilerEffectDuration += prevEffectDuration;
return elapsedTime;
}
十三、 组件效果
1. 重置组件效果计时器
export function resetComponentEffectTimers(): void {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return;
}
componentEffectStartTime = -1.1;
componentEffectEndTime = -1.1;
}
2. 添加组件效果
export function pushComponentEffectStart(): number {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return 0;
}
const prevEffectStart = componentEffectStartTime;
componentEffectStartTime = -1.1; // Track the next start.
return prevEffectStart;
}