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 itremainingLanes = 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 &¤t.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 deletedconst 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 deletedconst 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) {// Unmountconst 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,// 已完成的fibernearestMountedAncestor: 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;