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;
}
3. 弹出组件效果开始
export function popComponentEffectStart(prevEffectStart: number): void {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return;
}
// If the parent component didn't have a start time, we let this current time persist.
// 如果父组件没有开始时间,我们就让当前时间保持不变。
if (prevEffectStart >= 0) {
// Otherwise, we restore the previous parent's start time.
// 否则,我们将恢复之前父节点的开始时间。
componentEffectStartTime = prevEffectStart;
}
}
4. 推动组件效果持续时间
export function pushComponentEffectDuration(): number {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return 0;
}
const prevEffectDuration = componentEffectDuration;
// 重置组件级别持续时间。
componentEffectDuration = -0; // Reset component level duration.
return prevEffectDuration;
}
5. 弹出组件效果持续时间
export function popComponentEffectDuration(prevEffectDuration: number): void {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return;
}
// If the parent component didn't have a start time, we let this current time persist.
// 如果父组件没有开始时间,我们就让当前时间保持不变。
if (prevEffectDuration >= 0) {
// Otherwise, we restore the previous parent's start time.
// 否则,我们将恢复之前父项的开始时间。
componentEffectDuration = prevEffectDuration;
}
}
6. 推送组件效果错误
export function pushComponentEffectErrors(): null | Array<
CapturedValue<mixed>
> {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return null;
}
const prevErrors = componentEffectErrors;
componentEffectErrors = null;
return prevErrors;
}
7. 弹出组件效果错误
export function popComponentEffectErrors(
prevErrors: null | Array<CapturedValue<mixed>>,
): void {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return;
}
componentEffectErrors = prevErrors;
}
8. 推送组件效果已生成更新
export function pushComponentEffectDidSpawnUpdate(): boolean {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return false;
}
const prev = componentEffectSpawnedUpdate;
componentEffectSpawnedUpdate = false; // Reset.
return prev;
}
9. 弹出组件效果已生成更新
export function popComponentEffectDidSpawnUpdate(previousValue: boolean): void {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return;
}
componentEffectSpawnedUpdate = previousValue;
}
十四、当前更新是否嵌套
export function isCurrentUpdateNested(): boolean {
return currentUpdateIsNested;
}
十五、标记嵌套更新已安排
export function markNestedUpdateScheduled(): void {
if (enableProfilerNestedUpdatePhase) {
nestedUpdateScheduled = true;
}
}
十六、 重置嵌套更新标志
export function resetNestedUpdateFlag(): void {
if (enableProfilerNestedUpdatePhase) {
currentUpdateIsNested = false;
nestedUpdateScheduled = false;
}
}
十七、同步嵌套更新标志
export function syncNestedUpdateFlag(): void {
if (enableProfilerNestedUpdatePhase) {
currentUpdateIsNested = nestedUpdateScheduled;
nestedUpdateScheduled = false;
}
}
十八、记录时间
1. 记录渲染时间
export function recordRenderTime(): void {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return;
}
renderStartTime = now();
}
2. 记录提交时间
export function recordCommitTime(): void {
if (!enableProfilerTimer) {
return;
}
commitStartTime = now();
}
3. 记录提交结束时间
export function recordCommitEndTime(): void {
if (!enableProfilerTimer) {
return;
}
commitEndTime = now();
}
十九、性能分析计时器
1. 启动性能分析计时器
export function startProfilerTimer(fiber: Fiber): void {
if (!enableProfilerTimer) {
return;
}
profilerStartTime = now();
if (((fiber.actualStartTime: any): number) < 0) {
fiber.actualStartTime = profilerStartTime;
}
}
2. 如果正在运行则停止分析器计时器
export function stopProfilerTimerIfRunning(fiber: Fiber): void {
if (!enableProfilerTimer) {
return;
}
profilerStartTime = -1;
}
3. 如果正在运行则停止分析器计时器并记录持续时间
export function stopProfilerTimerIfRunningAndRecordDuration(
fiber: Fiber,
): void {
if (!enableProfilerTimer) {
return;
}
if (profilerStartTime >= 0) {
const elapsedTime = now() - profilerStartTime;
fiber.actualDuration += elapsedTime;
fiber.selfBaseDuration = elapsedTime;
profilerStartTime = -1;
}
}
4. 如果正在运行则停止分析器计时器并记录未完成的持续时间
export function stopProfilerTimerIfRunningAndRecordIncompleteDuration(
fiber: Fiber,
): void {
if (!enableProfilerTimer) {
return;
}
if (profilerStartTime >= 0) {
const elapsedTime = now() - profilerStartTime;
fiber.actualDuration += elapsedTime;
// We don't update the selfBaseDuration here because we errored.
// 我们没有在这里更新 selfBaseDuration,因为我们出错了。
profilerStartTime = -1;
}
}
5. 记录效果持续时间
export function recordEffectDuration(fiber: Fiber): void {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return;
}
if (profilerStartTime >= 0) {
const endTime = now();
const elapsedTime = endTime - profilerStartTime;
profilerStartTime = -1;
// Store duration on the next nearest Profiler ancestor
// Or the root (for the DevTools Profiler to read)
//
// 将持续时间存储在下一个最近的 Profiler 祖先节点上
// 或根节点(以便 DevTools Profiler 读取)
profilerEffectDuration += elapsedTime;
componentEffectDuration += elapsedTime;
// Keep track of the last end time of the effects.
// 记录效果的最后结束时间。
componentEffectEndTime = endTime;
}
}
6. 记录效果错误
export function recordEffectError(errorInfo: CapturedValue<mixed>): void {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return;
}
if (componentEffectErrors === null) {
componentEffectErrors = [];
}
componentEffectErrors.push(errorInfo);
if (commitErrors === null) {
commitErrors = [];
}
commitErrors.push(errorInfo);
}
7. 重置提交错误
export function resetCommitErrors(): void {
commitErrors = null;
}
8. 启动效果计时器
export function startEffectTimer(): void {
if (!enableProfilerTimer || !enableProfilerCommitHooks) {
return;
}
profilerStartTime = now();
if (componentEffectStartTime < 0) {
// Keep track of the first time we start an effect as the component's effect start time.
// 记录第一次启动 effect 的时间,作为组件的 effect 开始时间。
componentEffectStartTime = profilerStartTime;
}
}
9. 实际传输时长
export function transferActualDuration(fiber: Fiber): void {
// Transfer time spent rendering these children so we don't lose it
// after we rerender. This is used as a helper in special cases
// where we should count the work of multiple passes.
//
// 转移渲染这些子元素所花费的时间,以免在重新渲染后丢失
// 这在某些特殊情况下作为辅助使用
// 在这些情况下,我们应该计算多次渲染的工作时间。
let child = fiber.child;
while (child) {
fiber.actualDuration += child.actualDuration;
child = child.sibling;
}
}
10. 开始动画
export function startAnimating(lanes: Lanes): void {
animatingLanes |= lanes;
animatingTask = null;
}
11. 停止动画
export function stopAnimating(lanes: Lanes): void {
animatingLanes &= ~lanes;
animatingTask = null;
}
12. 跟踪动画任务
export function trackAnimatingTask(task: ConsoleTask): void {
if (animatingTask === null) {
animatingTask = task;
}
}
二十、变量
1. 当前更新是嵌套的
备注
源码的 522 - 538 行
/**
* Tracks whether the current update was a nested/cascading
* update (scheduled from a layout effect).
*
* The overall sequence is:
* 1. render
* 2. commit (and call `onRender`, `onCommit`)
* 3. check for nested updates
* 4. flush passive effects (and call `onPostCommit`)
*
* Nested updates are identified in step 3 above,
* but step 4 still applies to the work that was just committed.
* We use two flags to track nested updates then:
* one tracks whether the upcoming update is a nested update,
* and the other tracks whether the current update was a nested update.
* The first value gets synced to the second at the start of the render phase.
*/
/**
* 跟踪当前更新是否为嵌套/级联更新(由布局效果调度)。
*
* 整体顺序是:
* 1. 渲染
* 2. 提交(并调用 `onRender`、`onCommit`)
* 3. 检查嵌套更新
* 4. 刷新被动效果(并调用 `onPostCommit`)
*
* 嵌套更新在上面的步骤 3 中被识别,
* 但步骤 4 仍适用于刚刚提交的工作。
* 我们使用两个标志来跟踪嵌套更新:
* 一个标志跟踪即将进行的更新是否为嵌套更新,
* 另一个标志跟踪当前更新是否为嵌套更新。
* 第一个值将在渲染阶段开始时同步到第二个。
*/
let currentUpdateIsNested: boolean = false;
2. 下次更新已安排
备注
源码中的
lte nestedUpdateScheduled: boolean = false;