commitRoot入口
在finishConcurrentRender函数,commitRootWhenReady函数,commitRoot函数。
commitRoot流程图
commitRoot函数
commitRoot
函数是 React 渲染流程中用于提交根节点的关键函数。它的主要作用是设置相关的优先级和状态,然后调用 commitRootImpl
函数来实际执行根节点的提交操作,最后在操作完成后恢复之前的状态。
函数参数含义
- root: 类型为 FiberRoot,代表 React 应用的根节点,包含了整个应用的渲染信息。
- recoverableErrors: 类型为 null | Array<CapturedValue<mixed>>,是一个可恢复错误的数组,用于处理在渲染过程中捕获到的可恢复错误。
- transitions: 类型为 Array<Transition> | null,表示渲染过程中涉及的过渡任务数组。
- didIncludeRenderPhaseUpdate: 布尔类型,指示渲染阶段是否包含更新操作。
- spawnedLane: 类型为 Lane,表示在渲染过程中产生的新的渲染优先级车道。
- updatedLanes: 类型为 Lanes,表示在渲染过程中更新的渲染优先级车道。
- suspendedRetryLanes: 类型为 Lanes,表示暂停后重试的渲染优先级车道。
- suspendedCommitReason: 类型为 SuspendedCommitReason,是一个仅用于性能分析的参数,指示提交操作被暂停的原因。
- completedRenderStartTime: 数值类型,是一个仅用于性能分析的参数,记录渲染开始的时间。
- completedRenderEndTime: 数值类型,是一个仅用于性能分析的参数,记录渲染结束的时间。
function commitRoot(
root: FiberRoot,
recoverableErrors: null | Array<CapturedValue<mixed>>,
transitions: Array<Transition> | null,
didIncludeRenderPhaseUpdate: boolean,
spawnedLane: Lane,
updatedLanes: Lanes,
suspendedRetryLanes: Lanes,
// suspendedCommitReason: SuspendedCommitReason, // Profiling-only
// completedRenderStartTime: number, // Profiling-only
// completedRenderEndTime: number, // Profiling-only
) {
const prevTransition = ReactSharedInternals.T;
const previousUpdateLanePriority = getCurrentUpdatePriority();
try {
// 设置新的更新优先级并清空过渡状态
setCurrentUpdatePriority(DiscreteEventPriority);
ReactSharedInternals.T = null;
commitRootImpl(
root,
recoverableErrors,
transitions,
didIncludeRenderPhaseUpdate,
previousUpdateLanePriority,
spawnedLane,
updatedLanes,
suspendedRetryLanes,
suspendedCommitReason,
completedRenderStartTime,
completedRenderEndTime,
);
} finally {
// 恢复之前的状态
ReactSharedInternals.T = prevTransition;
setCurrentUpdatePriority(previousUpdateLanePriority);
}
}
commitRootImpl函数
commitRootImpl
函数是 React 渲染流程中用于提交根节点的核心函数,它负责将渲染阶段生成的结果应用到实际的 DOM 上,并执行相关的副作用操作。
- 更新 DOM:将
Fiber
树的变化应用到真实的 DOM 上,完成视图的更新。 - 执行副作用:处理各种副作用,包括
useEffect
、useLayoutEffect
等钩子函数的执行,以及生命周期方法的调用。 - 清理和重置状态:在提交完成后,清理和重置相关的状态,为下一次渲染做准备
function commitRootImpl(
root: FiberRoot,
recoverableErrors: null | Array<CapturedValue<mixed>>,
transitions: Array<Transition> | null,
didIncludeRenderPhaseUpdate: boolean,
renderPriorityLevel: EventPriority,
spawnedLane: Lane,
updatedLanes: Lanes,
suspendedRetryLanes: Lanes,
// suspendedCommitReason: SuspendedCommitReason, // Profiling-only
// completedRenderStartTime: number, // Profiling-only
// completedRenderEndTime: number, // Profiling-only
) {
// 循环调用 flushPassiveEffects 函数,直到没有待处理的被动副作用。
// 被动副作用通常包括 useEffect 钩子函数的执行。
do {
flushPassiveEffects();
} while (rootWithPendingPassiveEffects !== null);
// 获取已完成的 Fiber 树(finishedWork)和已完成的优先级车道(lanes)。
const finishedWork = root.finishedWork;
const lanes = root.finishedLanes;
// 如果没有已完成的 Fiber 树,则直接返回。
if (finishedWork === null) {
return null;
}
// 将 root.finishedWork 和 root.finishedLanes 重置。
root.finishedWork = null;
root.finishedLanes = NoLanes;
// 重置根节点的回调节点、回调优先级和取消待提交的状态。
root.callbackNode = null;
root.callbackPriority = NoLane;
root.cancelPendingCommit = null;
// 合并 finishedWork 的车道和子车道,得到剩余的优先级车道
let remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);
// 获取在渲染阶段并发更新的车道。
const concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes();
// 合并车道
remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes);
// 将 didIncludeCommitPhaseUpdate 标志重置为 false,用于检测提交阶段是否有递归更新。
didIncludeCommitPhaseUpdate = false;
// 如果根节点和工作进度根节点一致,则重置相关状态。
if (root === workInProgressRoot) {
// We can reset these now that they are finished.
workInProgressRoot = null;
workInProgress = null;
workInProgressRootRenderLanes = NoLanes;
}
// 检查子树是否有 BeforeMutation、Mutation、Layout 或 Passive 副作用。
const subtreeHasEffects =
(finishedWork.subtreeFlags &
(BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==
NoFlags;
// 检查根节点是否有 BeforeMutation、Mutation、Layout 或 Passive 副作用。
const rootHasEffect =
(finishedWork.flags &
(BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==
NoFlags;
if (subtreeHasEffects || rootHasEffect) {
const prevTransition = ReactSharedInternals.T;
ReactSharedInternals.T = null;
const previousPriority = getCurrentUpdatePriority();
setCurrentUpdatePriority(DiscreteEventPriority);
const prevExecutionContext = executionContext;
executionContext |= CommitContext;
// Before Mutation 阶段
const shouldFireAfterActiveInstanceBlur = commitBeforeMutationEffects(
root,
finishedWork,
);
// Mutation 阶段
// 执行 commitMutationEffects 函数,将 Fiber 树的变化应用到真实的 DOM 上。
commitMutationEffects(root, finishedWork, lanes);
if (enableCreateEventHandleAPI) {
if (shouldFireAfterActiveInstanceBlur) {
afterActiveInstanceBlur();
}
}
resetAfterCommit(root.containerInfo);
root.current = finishedWork;
// Layout 阶段
// 执行 commitLayoutEffects 函数,调用 useLayoutEffect 钩子函数和相关的生命周期方法。
commitLayoutEffects(finishedWork, root, lanes);
// 请求浏览器进行绘制,更新视图。
requestPaint();
// 恢复上下文和优先级
executionContext = prevExecutionContext;
setCurrentUpdatePriority(previousPriority);
ReactSharedInternals.T = prevTransition;
} else {
// No effects.
root.current = finishedWork;
}
const rootDidHavePassiveEffects = rootDoesHavePassiveEffects;
// 如果根节点有被动副作用,则将相关状态存储起来,等待后续处理;否则,释放根节点的缓存池。
if (rootDoesHavePassiveEffects) {
rootDoesHavePassiveEffects = false;
rootWithPendingPassiveEffects = root;
pendingPassiveEffectsLanes = lanes;
} else {
releaseRootPooledCache(root, remainingLanes);
}
// Read this again, since an effect might have updated it
// 获取根节点的待处理优先级车道,如果没有剩余工作,则清除已失败的错误边界。
remainingLanes = root.pendingLanes;
//处理剩余工作和调度
if (remainingLanes === NoLanes) {
legacyErrorBoundariesThatAlreadyFailed = null;
}
// 确保根节点被正确调度,以便处理后续的更新。
ensureRootIsScheduled(root);
// Read this again, since a passive effect might have updated it
remainingLanes = root.pendingLanes;
// 检测无限更新循环,检测是否存在无限更新循环,若存在则增加嵌套更新计数。
if (
(enableInfiniteRenderLoopDetection &&
(didIncludeRenderPhaseUpdate || didIncludeCommitPhaseUpdate)) ||
// Was the finished render the result of an update (not hydration)?
(includesSomeLane(lanes, UpdateLanes) &&
// Did it schedule a sync update?
includesSomeLane(remainingLanes, SyncUpdateLanes))
) {
if (root === rootWithNestedUpdates) {
nestedUpdateCount++;
} else {
nestedUpdateCount = 0;
rootWithNestedUpdates = root;
}
} else {
nestedUpdateCount = 0;
}
// If layout work was scheduled, flush it now.
// 刷新同步工作
flushSyncWorkOnAllRoots();
return null;
}
当根节点或子节点存在BeforeMutation、Mutation、Layout 或 Passiv副作用时,会执行:
- commitBeforeMutationEffects,是 React 渲染流程中提交阶段的一部分,主要用于在进行 DOM 突变(如更新、插入、删除节点)之前执行一些必要的准备工作和副作用操作。该函数会处理焦点管理、标记需要执行的副作用,并返回一个布尔值,指示是否应该触发在活动实例失去焦点后执行的回调。
- commitMutationEffects,数是 React 渲染流程中提交阶段的关键部分,它主要负责执行 DOM 突变(如插入、更新、删除节点)相关的副作用操作。此函数会在 React 完成协调阶段(reconciliation)后,将计算出的 DOM 变更应用到实际的 DOM 树上。
- commitLayoutEffects,是 React 提交阶段(Commit Phase)中的一个关键函数,主要负责执行布局副作用(Layout Effects)。在 React 的渲染流程中,当协调阶段(Reconciliation Phase)完成后,会进入提交阶段,这个阶段会将协调阶段计算出的变更应用到实际的 DOM 上。布局副作用是在 DOM 更新后立即执行的副作用,通常用于获取 DOM 节点的布局信息,如元素的宽度、高度等。
- requestPaint,用于请求浏览器进行一次重绘操作。
flushPassiveEffects函数
flushPassiveEffects
函数主要用于处理 React 中的被动副作用(passive effects)。被动副作用通常是指在渲染完成后异步执行的副作用,例如 useEffect
钩子中的一些操作。该函数会检查是否存在待处理的被动副作用,如果存在,则调用 flushPassiveEffectsImpl
函数来实际执行这些副作用,并在执行前后进行状态的保存和恢复,确保操作的正确性和状态的一致性。
function flushPassiveEffects(wasDelayedCommit?: boolean): boolean {
// rootWithPendingPassiveEffects 是一个全局变量,用于存储存在待处理被动副作用的根节点。
//如果该变量不为 null,则表示存在待处理的被动副作用,继续执行后续操作。
if (rootWithPendingPassiveEffects !== null) {
// 获取存在待处理被动副作用的根节点。
const root = rootWithPendingPassiveEffects;
// 获取待处理被动副作用剩余的渲染优先级车道。
const remainingLanes = pendingPassiveEffectsRemainingLanes;
// 将待处理被动副作用剩余的渲染优先级车道重置为 NoLanes,表示已经开始处理这些副作用。
pendingPassiveEffectsRemainingLanes = NoLanes;
// lanesToEventPriority 函数将待处理被动副作用的渲染优先级车道转换为事件优先级。
const renderPriority = lanesToEventPriority(pendingPassiveEffectsLanes);
// 调用 lowerEventPriority 函数,取 DefaultEventPriority 和 renderPriority 中的较低优先级作为最终的执行优先级
const priority = lowerEventPriority(DefaultEventPriority, renderPriority);
const prevTransition = ReactSharedInternals.T;
// 当前的更新优先级
const previousPriority = getCurrentUpdatePriority();
try {
setCurrentUpdatePriority(priority);
ReactSharedInternals.T = null;
// 调用 flushPassiveEffectsImpl 函数实际执行被动副作用,并返回该函数的执行结果。
return flushPassiveEffectsImpl(wasDelayedCommit);
} finally {
// 恢复之前的状态并释放根节点的缓存
setCurrentUpdatePriority(previousPriority);
ReactSharedInternals.T = prevTransition;
// 释放根节点的缓存,传入根节点和剩余的渲染优先级车道作为参数。
releaseRootPooledCache(root, remainingLanes);
}
}
// 不存在待处理的被动副作用,直接返回 false。
return false;
}
flushPassiveEffectsImpl
flushPassiveEffectsImpl
函数的主要作用是刷新待处理的被动副作用。被动副作用通常和 React 的 useEffect
钩子相关,在渲染完成后异步执行。此函数会处理组件卸载和挂载时的被动副作用,同时处理过渡回调和同步工作。
function flushPassiveEffectsImpl(wasDelayedCommit: void | boolean) {
// 检查是否有待处理的被动副作用
if (rootWithPendingPassiveEffects === null) {
return false;
}
// Cache and clear the transitions flag
// 缓存并清除过渡标志
const transitions = pendingPassiveTransitions;
pendingPassiveTransitions = null;
// 获取根节点和车道信息并重置
const root = rootWithPendingPassiveEffects;
const lanes = pendingPassiveEffectsLanes;
rootWithPendingPassiveEffects = null;
pendingPassiveEffectsLanes = NoLanes;
// 检查是否正在渲染
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
throw new Error('Cannot flush passive effects while already rendering.');
}
// 记录开始时间并设置执行上下文
let passiveEffectStartTime = 0;
const prevExecutionContext = executionContext;
executionContext |= CommitContext;
// 执行被动卸载和挂载副作用
commitPassiveUnmountEffects(root.current);
commitPassiveMountEffects(
root,
root.current,
lanes,
transitions,
pendingPassiveEffectsRenderEndTime,
);
// 恢复执行上下文
executionContext = prevExecutionContext;
// 刷新所有根节点的同步工作
flushSyncWorkOnAllRoots();
// 若启用了过渡跟踪功能,缓存当前的过渡回调、根节点过渡回调和结束时间。若这些值都不为 null,将当前的过渡回调和结束时间重置为 null,并在空闲调度优先级下调度 processTransitionCallbacks 函数来处理过渡回调。
if (enableTransitionTracing) {
const prevPendingTransitionCallbacks = currentPendingTransitionCallbacks;
const prevRootTransitionCallbacks = root.transitionCallbacks;
const prevEndTime = currentEndTime;
if (
prevPendingTransitionCallbacks !== null &&
prevRootTransitionCallbacks !== null &&
prevEndTime !== null
) {
currentPendingTransitionCallbacks = null;
currentEndTime = null;
scheduleCallback(IdleSchedulerPriority, () => {
processTransitionCallbacks(
prevPendingTransitionCallbacks,
prevEndTime,
prevRootTransitionCallbacks,
);
});
}
}
return true;
}
commitPassiveUnmountEffects
function commitPassiveUnmountEffects(finishedWork: Fiber): void {
// resetComponentEffectTimers();
commitPassiveUnmountOnFiber(finishedWork);
}
commitPassiveUnmountOnFiber
commitPassiveUnmountOnFiber
函数的主要作用是在 React 渲染流程的提交阶段,对指定的 Fiber
节点执行被动卸载副作用的操作。被动卸载副作用通常与 useEffect
钩子的清理函数相关,当组件卸载时,这些清理函数会被调用。该函数会根据 Fiber
节点的不同类型,执行相应的卸载逻辑。
function commitPassiveUnmountOnFiber(finishedWork: Fiber): void {
// const prevEffectStart = pushComponentEffectStart();
switch (finishedWork.tag) {
case FunctionComponent:
case ForwardRef:
case SimpleMemoComponent: {
recursivelyTraversePassiveUnmountEffects(finishedWork);
if (finishedWork.flags & Passive) {
commitHookPassiveUnmountEffects(
finishedWork,
finishedWork.return,
HookPassive | HookHasEffect,
);
}
break;
}
case HostRoot: {
// const prevEffectDuration = pushNestedEffectDurations();
recursivelyTraversePassiveUnmountEffects(finishedWork);
break;
}
case Profiler: {
// const prevEffectDuration = pushNestedEffectDurations();
recursivelyTraversePassiveUnmountEffects(finishedWork);
break;
}
case OffscreenComponent: {
const instance: OffscreenInstance = finishedWork.stateNode;
const nextState: OffscreenState | null = finishedWork.memoizedState;
const isHidden = nextState !== null;
if (
isHidden &&
instance._visibility & OffscreenPassiveEffectsConnected &&
(finishedWork.return === null ||
finishedWork.return.tag !== SuspenseComponent)
) {
instance._visibility &= ~OffscreenPassiveEffectsConnected;
recursivelyTraverseDisconnectPassiveEffects(finishedWork);
} else {
recursivelyTraversePassiveUnmountEffects(finishedWork);
}
break;
}
default: {
recursivelyTraversePassiveUnmountEffects(finishedWork);
break;
}
}
// popComponentEffectStart(prevEffectStart);
}
recursivelyTraversePassiveUnmountEffects
递归遍历 Fiber
树,处理组件卸载时的被动副作用(如 useEffect
的清理函数)。它主要处理两类逻辑:
- 子节点删除:当父节点标记为需要删除子节点(
ChildDeletion
)时,遍历所有待删除的子节点,执行其被动卸载副作用。 - 子树被动副作用:遍历父节点的子树,对每个子节点调用
commitPassiveUnmountOnFiber
,处理其被动卸载逻辑。
function recursivelyTraversePassiveUnmountEffects(parentFiber: Fiber): void {
const deletions = parentFiber.deletions;
// 如果父节点有子节点需要删除
if ((parentFiber.flags & ChildDeletion) !== NoFlags) {
if (deletions !== null) {
for (let i = 0; i < deletions.length; i++) {
const childToDelete = deletions[i];
//当前要删除的子节点
nextEffect = childToDelete;
// 在子节点被删除前,执行其被动卸载副作用。
commitPassiveUnmountEffectsInsideOfDeletedTree_begin(
childToDelete,
parentFiber,
);
}
}
// 断开已删除子节点的兄弟节点与旧 Fiber 树(alternate 指针)的连接,避免残留引用导致内存泄漏。
detachAlternateSiblings(parentFiber);
}
// 遍历子树处理被动副作用
if (parentFiber.subtreeFlags & PassiveMask) {
let child = parentFiber.child;
while (child !== null) {
// 深度优先
commitPassiveUnmountOnFiber(child);
// 兄弟节点(广度优先)
child = child.sibling;
}
}
}
commitPassiveUnmountEffectsInsideOfDeletedTree_begin
主要功能是在删除子树时,递归地执行该子树中所有 Fiber
节点的被动卸载副作用。它会遍历子树中的每个 Fiber
节点,对每个节点调用 commitPassiveUnmountInsideDeletedTreeOnFiber
函数来执行具体的卸载逻辑。
function commitPassiveUnmountEffectsInsideOfDeletedTree_begin(
deletedSubtreeRoot: Fiber,
nearestMountedAncestor: Fiber | null,
) {
// 循环遍历 Fiber 节点
while (nextEffect !== null) {
const fiber = nextEffect;
commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor);
// 处理子节点
const child = fiber.child;
if (child !== null) {
child.return = fiber;
nextEffect = child;
} else {
commitPassiveUnmountEffectsInsideOfDeletedTree_complete(
deletedSubtreeRoot,
);
}
}
}
commitPassiveUnmountEffectsInsideOfDeletedTree_complete
ommitPassiveUnmountEffectsInsideOfDeletedTree_complete
函数的主要功能是在删除子树的被动卸载副作用处理完成后,对删除子树中的 Fiber
节点进行清理工作,确保内存能够被正确释放,避免出现内存泄漏问题。它会遍历子树中的 Fiber
节点,逐个清理节点及其关联资源,并且在遍历过程中根据节点的兄弟节点和父节点信息进行路径回溯。
function commitPassiveUnmountEffectsInsideOfDeletedTree_complete(
deletedSubtreeRoot: Fiber,
) {
// 循环遍历 Fiber 节点
while (nextEffect !== null) {
const fiber = nextEffect;
const sibling = fiber.sibling;
const returnFiber = fiber.return;
// 清理 Fiber 节点及其关联的资源,确保内存释放和旧节点引用断开。
detachFiberAfterEffects(fiber);
// 判断是否到达删除子树的根节点
if (fiber === deletedSubtreeRoot) {
nextEffect = null;
return;
}
// 处理兄弟节点
if (sibling !== null) {
sibling.return = returnFiber;
nextEffect = sibling;
return;
}
// 回溯父节点
nextEffect = returnFiber;
}
}
commitPassiveUnmountInsideDeletedTreeOnFiber
function commitPassiveUnmountInsideDeletedTreeOnFiber(
current: Fiber,
nearestMountedAncestor: Fiber | null,
): void {
switch (current.tag) {
case FunctionComponent:
case ForwardRef:
case SimpleMemoComponent: {
commitHookPassiveUnmountEffects(
current,
nearestMountedAncestor,
HookPassive,
);
break;
}
case LegacyHiddenComponent:
case OffscreenComponent: {
if (enableCache) {
if (
current.memoizedState !== null &&
current.memoizedState.cachePool !== null
) {
const cache: Cache = current.memoizedState.cachePool.pool;
if (cache != null) {
retainCache(cache);
}
}
}
break;
}
case SuspenseComponent: {
if (enableTransitionTracing) {
// We need to mark this fiber's parents as deleted
const offscreenFiber: Fiber = (current.child: any);
const instance: OffscreenInstance = offscreenFiber.stateNode;
const transitions = instance._transitions;
if (transitions !== null) {
const abortReason = {
reason: 'suspense',
name: current.memoizedProps.unstable_name || null,
};
if (
current.memoizedState === null ||
current.memoizedState.dehydrated === null
) {
abortParentMarkerTransitionsForDeletedFiber(
offscreenFiber,
abortReason,
transitions,
instance,
true,
);
if (nearestMountedAncestor !== null) {
abortParentMarkerTransitionsForDeletedFiber(
nearestMountedAncestor,
abortReason,
transitions,
instance,
false,
);
}
}
}
}
break;
}
case CacheComponent: {
if (enableCache) {
const cache = current.memoizedState.cache;
releaseCache(cache);
}
break;
}
case TracingMarkerComponent: {
if (enableTransitionTracing) {
// We need to mark this fiber's parents as deleted
const instance: TracingMarkerInstance = current.stateNode;
const transitions = instance.transitions;
if (transitions !== null) {
const abortReason = {
reason: 'marker',
name: current.memoizedProps.name,
};
abortParentMarkerTransitionsForDeletedFiber(
current,
abortReason,
transitions,
null,
true,
);
if (nearestMountedAncestor !== null) {
abortParentMarkerTransitionsForDeletedFiber(
nearestMountedAncestor,
abortReason,
transitions,
null,
false,
);
}
}
}
break;
}
}
}
detachAlternateSiblings
detachAlternateSiblings
函数的主要作用是断开父 Fiber
节点旧版本(alternate
)的子节点之间的兄弟关系。
当需要清理旧的 Fiber
节点时,该函数会将旧 Fiber
节点的子节点之间的兄弟引用断开,从而辅助垃圾回收机制更有效地回收这些不再使用的旧节点。
function detachAlternateSiblings(parentFiber: Fiber) {
const previousFiber = parentFiber.alternate;
if (previousFiber !== null) {
// 检查旧版本父节点是否有子节点
let detachedChild = previousFiber.child;
if (detachedChild !== null) {
// 开父节点与第一个子节点的连接。
previousFiber.child = null;
// 遍历并断开子节点的兄弟关系
do {
// 下一个子节点(兄弟节点)
const detachedSibling = detachedChild.sibling;
//断开其与兄弟节点的连接。
detachedChild.sibling = null;
detachedChild = detachedSibling;
} while (detachedChild !== null);
}
}
}
commitPassiveUnmountOnFiber
commitPassiveUnmountOnFiber
函数的主要作用是在 React 渲染流程的提交阶段,对指定的 Fiber
节点执行被动卸载副作用的操作。被动卸载副作用通常与 useEffect
钩子的清理函数相关,当组件卸载时,这些清理函数会被调用。该函数会根据 Fiber
节点的不同类型,执行相应的卸载逻辑。
function commitPassiveUnmountOnFiber(finishedWork: Fiber): void {
// const prevEffectStart = pushComponentEffectStart();
switch (finishedWork.tag) {
case FunctionComponent:
case ForwardRef:
case SimpleMemoComponent: {
recursivelyTraversePassiveUnmountEffects(finishedWork);
if (finishedWork.flags & Passive) {
commitHookPassiveUnmountEffects(
finishedWork,
finishedWork.return,
HookPassive | HookHasEffect,
);
}
break;
}
case HostRoot: {
// const prevEffectDuration = pushNestedEffectDurations();
recursivelyTraversePassiveUnmountEffects(finishedWork);
break;
}
case Profiler: {
// const prevEffectDuration = pushNestedEffectDurations();
recursivelyTraversePassiveUnmountEffects(finishedWork);
break;
}
case OffscreenComponent: {
const instance: OffscreenInstance = finishedWork.stateNode;
const nextState: OffscreenState | null = finishedWork.memoizedState;
const isHidden = nextState !== null;
if (
isHidden &&
instance._visibility & OffscreenPassiveEffectsConnected &&
(finishedWork.return === null ||
finishedWork.return.tag !== SuspenseComponent)
) {
instance._visibility &= ~OffscreenPassiveEffectsConnected;
recursivelyTraverseDisconnectPassiveEffects(finishedWork);
} else {
recursivelyTraversePassiveUnmountEffects(finishedWork);
}
break;
}
default: {
recursivelyTraversePassiveUnmountEffects(finishedWork);
break;
}
}
// popComponentEffectStart(prevEffectStart);
}
commitHookPassiveUnmountEffects
function commitHookPassiveUnmountEffects(
finishedWork: Fiber,
nearestMountedAncestor: null | Fiber,
hookFlags: HookFlags,
) {
commitHookEffectListUnmount(
hookFlags,
finishedWork,
nearestMountedAncestor,
);
}
commitHookEffectListUnmount
commitHookEffectListUnmount
函数的主要功能是在 React 组件卸载时,对符合特定标志(flags
)的副作用钩子(如 useEffect
、useLayoutEffect
等)执行清理操作。在 React 中,副作用钩子可能会返回一个清理函数,用于在组件卸载时进行资源释放、取消订阅等操作,该函数就是负责调用这些清理函数的。
函数参数含义
flags
: 类型为HookFlags
,是一个位掩码,用于筛选需要执行卸载操作的副作用钩子。不同的标志代表不同类型的副作用钩子,例如Layout
标志可能对应useLayoutEffect
,Passive
标志可能对应useEffect
。finishedWork
: 类型为Fiber
,表示已经完成协调的Fiber
节点,该节点包含了组件的副作用钩子信息。nearestMountedAncestor
: 类型为Fiber | null
,表示距离finishedWork
最近的已挂载的祖先Fiber
节点,在执行清理操作时可能会用到。
function commitHookEffectListUnmount(
flags: HookFlags,
finishedWork: Fiber,
nearestMountedAncestor: Fiber | null,
) {
try {
// 获取副作用队列
const updateQueue = finishedWork.updateQueue;
// 获取最后一个
const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
if (lastEffect !== null) {
const firstEffect = lastEffect.next;
let effect = firstEffect;
do {
// 检查当前副作用的 tag 是否与传入的 flags 匹配。如果匹配,说明该副作用需要执行卸载操作。
if ((effect.tag & flags) === flags) {
// Unmount
const inst = effect.inst;
const destroy = inst.destroy;
if (destroy !== undefined) {
// 将 inst.destroy 设置为 undefined,表示清理函数已经执行过
inst.destroy = undefined;
// 调用 safelyCallDestroy 函数安全地执行清理函数
safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy);
}
}
effect = effect.next;
} while (effect !== firstEffect);
}
} catch (error) {
// captureCommitPhaseError(finishedWork, finishedWork.return, error);
}
}
flushSyncWorkOnAllRoots
function performSyncWorkOnRoot(root: FiberRoot, lanes: Lanes) {
// This is the entry point for synchronous tasks that don't go
// through Scheduler.
const didFlushPassiveEffects = flushPassiveEffects();
if (didFlushPassiveEffects) {
return null;
}
const forceSync = true;
performWorkOnRoot(root, lanes, forceSync);
}
工具函数之 detachFiberAfterEffects
detachFiberAfterEffects
函数的作用是在 React 组件卸载或更新完成后,清理 Fiber
节点及其关联的资源,确保内存释放和旧节点引用断开。它主要用于处理已完成副作用(如 DOM 更新、钩子回调)的 Fiber
节点,避免内存泄漏,并为后续的垃圾回收做准备。
function detachFiberAfterEffects(fiber: Fiber) {
// 断开 alternate 引用并递归清理
const alternate = fiber.alternate;
if (alternate !== null) {
fiber.alternate = null;
detachFiberAfterEffects(alternate);
}
// 清空子节点和副作用相关属性
fiber.child = null;
fiber.deletions = null;
fiber.sibling = null;
// 处理宿主组件(如 DOM 节点)
if (fiber.tag === HostComponent) {
const hostInstance: Instance = fiber.stateNode;
if (hostInstance !== null) {
// 调用该函数清理 DOM 节点的关联资源(如事件监听器、自定义数据),确保 DOM 节点安全卸载。
detachDeletedInstance(hostInstance);
}
}
// 清空 stateNode(指向真实 DOM 节点的引用),避免内存泄漏。
fiber.stateNode = null;
// 重置 Fiber 节点状态
fiber.return = null;
fiber.dependencies = null;
fiber.memoizedProps = null;
fiber.memoizedState = null;
fiber.pendingProps = null;
fiber.stateNode = null;
fiber.updateQueue = null;
}
工具函数之 detachDeletedInstance
function detachDeletedInstance(node: Instance): void {
delete (node: any)[internalInstanceKey];
delete (node: any)[internalPropsKey];
delete (node: any)[internalEventHandlersKey];
delete (node: any)[internalEventHandlerListenersKey];
delete (node: any)[internalEventHandlesSetKey];
}
const randomKey = Math.random().toString(36).slice(2);
const internalInstanceKey = '__reactFiber$' + randomKey;
const internalPropsKey = '__reactProps$' + randomKey;
const internalContainerInstanceKey = '__reactContainer$' + randomKey;
const internalEventHandlersKey = '__reactEvents$' + randomKey;
const internalEventHandlerListenersKey = '__reactListeners$' + randomKey;
const internalEventHandlesSetKey = '__reactHandles$' + randomKey;
const internalRootNodeResourcesKey = '__reactResources$' + randomKey;
const internalHoistableMarker = '__reactMarker$' + randomKey;
工具函数之 lanesToEventPriority
lanesToEventPriority
函数的主要功能是将 React 的车道(Lanes
)转换为对应的事件优先级(EventPriority
)。在 React 的并发模式下,车道系统用于管理不同优先级的更新任务,而事件优先级则用于确定事件处理的紧急程度。该函数会根据传入的车道信息,找出最高优先级的车道,并将其映射为合适的事件优先级。
参数lanes
:类型为 Lanes
,表示一组车道。在 React 中,Lanes
是一种用于表示多个优先级车道的位掩码数据结构,每个车道代表一个不同的优先级。
function lanesToEventPriority(lanes: Lanes): EventPriority {
// 获取最高优先级的车道
const lane = getHighestPriorityLane(lanes);
// 判断并返回离散事件优先级
if (!isHigherEventPriority(DiscreteEventPriority, lane)) {
return DiscreteEventPriority;
}
// 判断并返回连续事件优先级
if (!isHigherEventPriority(ContinuousEventPriority, lane)) {
return ContinuousEventPriority;
}
// 判断 lane 是否包含非空闲工作。
if (includesNonIdleWork(lane)) {
return DefaultEventPriority;
}
// 返回空闲事件优先级
return IdleEventPriority;
}
// 表示没有事件优先级,它被映射到 NoLane。
const NoEventPriority: EventPriority = NoLane;
// 离散事件优先级,映射到 SyncLane。离散事件通常是指那些由用户交互触发的不连续事件,如点击、输入等。SyncLane 表示同步车道,这类事件的更新任务会被立即同步执行,以保证用户交互的即时响应。
const DiscreteEventPriority: EventPriority = SyncLane;
// 连续事件优先级,对应 InputContinuousLane。连续事件一般是指那些持续的用户交互事件,如滚动、拖动等。InputContinuousLane 用于处理这类连续事件的更新任务,确保在连续交互过程中页面的流畅性。
const ContinuousEventPriority: EventPriority = InputContinuousLane;
// 默认事件优先级,映射到 DefaultLane。当没有指定特定的事件优先级时,会使用默认优先级。DefaultLane 是一种通用的车道,用于处理大多数普通的更新任务。
const DefaultEventPriority: EventPriority = DefaultLane;
// 空闲事件优先级,对应 IdleLane。空闲事件是指那些在浏览器空闲时才会执行的任务,对实时性要求较低。IdleLane 中的任务会在浏览器有空闲资源时才会被执行,以避免影响其他高优先级任务的执行。
const IdleEventPriority: EventPriority = IdleLane;
工具函数之 lowerEventPriority
lowerEventPriority
函数的主要功能是比较两个事件优先级(EventPriority
),并返回其中较低的优先级。在 React 的协调和调度机制中,事件优先级用于决定不同任务的执行顺序,确保高优先级的任务能够优先得到处理。
函数参数含义
a
:类型为EventPriority
,代表第一个需要比较的事件优先级。b
:类型为EventPriority
,代表第二个需要比较的事件优先级。
使用三元运算符进行条件判断,具体逻辑如下:
a === 0
:如果a
的值为 0,在 React 的优先级体系中,0 可能代表一种特殊的优先级(如最高优先级或者无优先级的特殊情况),此时直接返回a
。a > b
:如果a
的值大于b
,根据 React 中事件优先级的定义,值越大优先级越低,所以返回a
。- 其他情况:如果上述两个条件都不满足,即
a
不为 0 且a
小于等于b
,则返回b
。
function lowerEventPriority(
a: EventPriority,
b: EventPriority,
): EventPriority {
return a === 0 || a > b ? a : b;
}
工具函数之 mergeLanes
mergeLanes
函数的主要功能是合并两个车道(Lanes
或单个 Lane
)。在 React 的调度系统里,车道(Lanes
)机制用于对不同更新任务的优先级进行管理和区分。该函数借助按位或运算符 |
把两个车道合并成一个新的车道,从而将多个更新任务的优先级信息整合起来。
function mergeLanes(a: Lanes | Lane, b: Lanes | Lane): Lanes {
return a | b;
}
const LaneA = 0b0001; // 二进制表示,代表第 1 个车道
const LaneB = 0b0010; // 二进制表示,代表第 2 个车道
const mergedLanes = mergeLanes(LaneA, LaneB);
console.log(mergedLanes.toString(2)); // 输出: 0b0011,代表第 1 个和第 2 个车道的合并
工具函数之 getCurrentUpdatePriority
function getCurrentUpdatePriority(): EventPriority {
return currentUpdatePriority;
}
工具函数之 setCurrentUpdatePriority
let currentUpdatePriority: EventPriority = NoEventPriority;
function setCurrentUpdatePriority(newPriority: EventPriority): void {
currentUpdatePriority = newPriority;
}
工具函数之 safelyCallDestroy
function safelyCallDestroy(
current: Fiber,// 已完成的fiber
nearestMountedAncestor: Fiber | null,
destroy: () => void,
) {
try {
// 执行清理回调函数
destroy();
} catch (error) {
// captureCommitPhaseError(current, nearestMountedAncestor, error);
}
}
工具函数之 detachDeletedInstance
清除实例上的某些属性。调用该函数清理 DOM 节点的关联资源(如事件监听器、自定义数据),确保 DOM 节点安全卸载。
function detachDeletedInstance(node: Instance): void {
delete (node: any)[internalInstanceKey];
delete (node: any)[internalPropsKey];
delete (node: any)[internalEventHandlersKey];
delete (node: any)[internalEventHandlerListenersKey];
delete (node: any)[internalEventHandlesSetKey];
}
const randomKey = Math.random().toString(36).slice(2);
const internalInstanceKey = '__reactFiber$' + randomKey;
const internalPropsKey = '__reactProps$' + randomKey;
const internalContainerInstanceKey = '__reactContainer$' + randomKey;
const internalEventHandlersKey = '__reactEvents$' + randomKey;
const internalEventHandlerListenersKey = '__reactListeners$' + randomKey;
const internalEventHandlesSetKey = '__reactHandles$' + randomKey;
const internalRootNodeResourcesKey = '__reactResources$' + randomKey;
const internalHoistableMarker = '__reactMarker$' + randomKey;
全局变量之事件优先级
// 表示没有优先级(初始状态或无效状态)。
export const NoEventPriority: EventPriority = NoLane;
// 离散事件优先级,最高优先级。用于需要立即同步执行的操作,如用户交互(点击、键盘事件)、setState 同步更新。这类操作会打断其他低优先级任务,立即执行。
export const DiscreteEventPriority: EventPriority = SyncLane;
// 连续事件优先级,用于连续触发的事件(如鼠标移动、滚动)。这类操作允许中断低优先级任务,但可以与其他连续任务合并,避免过度渲染。
export const ContinuousEventPriority: EventPriority = InputContinuousLane;
// 默认优先级,用于普通的状态更新(如异步数据加载完成后的更新)。任务会在离散和连续事件之后执行,但比空闲任务优先。
export const DefaultEventPriority: EventPriority = DefaultLane;
// 空闲优先级,最低优先级。用于非紧急任务(如性能优化、统计上报),仅在浏览器空闲时执行,可能被高优先级任务中断或丢弃。
export const IdleEventPriority: EventPriority = IdleLane;
const TotalLanes = 31;
const NoLanes: Lanes = /* */ 0b0000000000000000000000000000000;
const NoLane: Lane = /* */ 0b0000000000000000000000000000000;
const SyncHydrationLane: Lane = /* */ 0b0000000000000000000000000000001;
const SyncLane: Lane = /* */ 0b0000000000000000000000000000010;
const SyncLaneIndex: number = 1;
const InputContinuousHydrationLane:Lane= /**/0b0000000000000000000000000000100;
const InputContinuousLane: Lane = /* */ 0b0000000000000000000000000001000;
const DefaultHydrationLane: Lane = /* */ 0b0000000000000000000000000010000;
const DefaultLane: Lane = /* */ 0b0000000000000000000000000100000;
const SyncUpdateLanes: Lane = SyncLane | InputContinuousLane | DefaultLane;