React19源碼閱讀之commitRoot

commitRoot入口

在finishConcurrentRender函數,commitRootWhenReady函數,commitRoot函數。

commitRoot流程圖

commitRoot函數

commitRoot 函數是 React 渲染流程中用于提交根節點的關鍵函數。它的主要作用是設置相關的優先級和狀態,然后調用 commitRootImpl 函數來實際執行根節點的提交操作,最后在操作完成后恢復之前的狀態。

函數參數含義

  1. root: 類型為 FiberRoot,代表 React 應用的根節點,包含了整個應用的渲染信息。
  2. recoverableErrors: 類型為 null | Array<CapturedValue<mixed>>,是一個可恢復錯誤的數組,用于處理在渲染過程中捕獲到的可恢復錯誤。
  3. transitions: 類型為 Array<Transition> | null,表示渲染過程中涉及的過渡任務數組。
  4. didIncludeRenderPhaseUpdate: 布爾類型,指示渲染階段是否包含更新操作。
  5. spawnedLane: 類型為 Lane,表示在渲染過程中產生的新的渲染優先級車道。
  6. updatedLanes: 類型為 Lanes,表示在渲染過程中更新的渲染優先級車道。
  7. suspendedRetryLanes: 類型為 Lanes,表示暫停后重試的渲染優先級車道。
  8. suspendedCommitReason: 類型為 SuspendedCommitReason,是一個僅用于性能分析的參數,指示提交操作被暫停的原因。
  9. completedRenderStartTime: 數值類型,是一個僅用于性能分析的參數,記錄渲染開始的時間。
  10. 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 上,并執行相關的副作用操作。

  1. 更新 DOM:將 Fiber 樹的變化應用到真實的 DOM 上,完成視圖的更新。
  2. 執行副作用:處理各種副作用,包括 useEffectuseLayoutEffect 等鉤子函數的執行,以及生命周期方法的調用。
  3. 清理和重置狀態:在提交完成后,清理和重置相關的狀態,為下一次渲染做準備
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副作用時,會執行:

  1. commitBeforeMutationEffects,是 React 渲染流程中提交階段的一部分,主要用于在進行 DOM 突變(如更新、插入、刪除節點)之前執行一些必要的準備工作和副作用操作。該函數會處理焦點管理、標記需要執行的副作用,并返回一個布爾值,指示是否應該觸發在活動實例失去焦點后執行的回調。
  2. commitMutationEffects,數是 React 渲染流程中提交階段的關鍵部分,它主要負責執行 DOM 突變(如插入、更新、刪除節點)相關的副作用操作。此函數會在 React 完成協調階段(reconciliation)后,將計算出的 DOM 變更應用到實際的 DOM 樹上。
  3. commitLayoutEffects,是 React 提交階段(Commit Phase)中的一個關鍵函數,主要負責執行布局副作用(Layout Effects)。在 React 的渲染流程中,當協調階段(Reconciliation Phase)完成后,會進入提交階段,這個階段會將協調階段計算出的變更應用到實際的 DOM 上。布局副作用是在 DOM 更新后立即執行的副作用,通常用于獲取 DOM 節點的布局信息,如元素的寬度、高度等。
  4. 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 的清理函數)。它主要處理兩類邏輯:

  1. 子節點刪除:當父節點標記為需要刪除子節點(ChildDeletion)時,遍歷所有待刪除的子節點,執行其被動卸載副作用。
  2. 子樹被動副作用:遍歷父節點的子樹,對每個子節點調用 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 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)的副作用鉤子(如 useEffectuseLayoutEffect 等)執行清理操作。在 React 中,副作用鉤子可能會返回一個清理函數,用于在組件卸載時進行資源釋放、取消訂閱等操作,該函數就是負責調用這些清理函數的。

函數參數含義

  • flags: 類型為 HookFlags,是一個位掩碼,用于篩選需要執行卸載操作的副作用鉤子。不同的標志代表不同類型的副作用鉤子,例如 Layout 標志可能對應 useLayoutEffectPassive 標志可能對應 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;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/902730.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/902730.shtml
英文地址,請注明出處:http://en.pswp.cn/news/902730.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

利用Python爬蟲實現百度圖片搜索的PNG圖片下載

在圖像識別、訓練數據集構建等場景中&#xff0c;我們經常需要從互聯網上批量下載圖片素材。百度圖片是中文搜索中最常用的來源之一。本文將介紹如何使用Python構建一個穩定、可擴展的百度圖片爬蟲&#xff0c;專門用于下載并保存高清PNG格式圖片。 一、項目目標 本項目的目標…

Axure復選框組件的深度定制:實現自定義大小、顏色與全選功能

在產品設計中&#xff0c;復選框作為用戶與界面交互的重要元素&#xff0c;其靈活性直接影響到用戶體驗。本文將介紹如何利用Axure RP工具&#xff0c;通過高級技巧實現復選框組件的自定義大小、顏色調整&#xff0c;以及全選功能的集成&#xff0c;為產品原型設計增添更多可能…

深度理解spring——BeanFactory的實現

BeanFactory Spring之BeanFactory什么是BeanFactoryApplicationContext相對BeanFactory實現的功能性擴展1. MessageSource2. ResourcePatternResolver3. ApplicationEventPublisher4. EnvironmentCapable通用ApplicationContext實踐實現BeanFactoryBeanFactory后處理器排序讓誰…

跑MPS產生委外采購申請(成品)

問題&#xff1a;跑MPS產生委外采購申請&#xff08;成品&#xff09;&#xff0c;更改BOM和跑MRP&#xff0c;但物料需求清單中無新增物料復合膜的需求。截圖如下&#xff1a; 解決方法&#xff1a;更改委外采購申請的批準日期為BOM的生效日和重新展開bom。 重新展開后&#x…

“在中國,為中國” 英飛凌汽車業務正式發布中國本土化戰略

3月28日&#xff0c;以“夯實電動化&#xff0c;推進智能化&#xff0c;實現高質量發展”為主題的2025中國電動汽車百人會論壇在北京舉辦。眾多中外機構與行業上下游嘉賓就全球及中國汽車電動化的發展現狀、面臨的挑戰與機遇&#xff0c;以及在技術創新、市場布局、供應鏈協同等…

優雅實現網頁彈窗提示功能:JavaScript與CSS完美結合

在現代Web開發中&#xff0c;彈窗提示是提升用戶體驗的重要元素之一。本文將深入探討如何實現一個優雅、可復用的彈窗提示系統&#xff0c;避免常見問題如重復觸發、樣式混亂等。 核心代碼解析 // 控制彈窗是否可以顯示的標志 let alertStatus true;// 顯示提示信息 functio…

YOLOv11改進-雙Backbone架構:利用雙backbone提高yolo11目標檢測的精度

一、引言&#xff1a;為什么我們需要雙Backbone&#xff1f; 在目標檢測任務中&#xff0c;YOLO系列模型因其高效的端到端檢測能力而備受青睞。然而&#xff0c;傳統YOLO模型大多采用單一Backbone結構&#xff0c;即利用一個卷積神經網絡&#xff08;CNN&#xff09;作為特征提…

用 PyQt5 和 asyncio 打造接口并發測試 GUI 工具

接口并發測試是測試工程師日常工作中的重要一環&#xff0c;而一個直觀的 GUI 工具能有效提升工作效率和體驗。本篇文章將帶你用 PyQt5 和 asyncio 從零實現一個美觀且功能實用的接口并發測試工具。 我們將實現以下功能&#xff1a; 請求方法選擇器 添加了一個下拉框 QComboBo…

理解npm的工作原理:優化你的項目依賴管理流程

目錄 什么是npm npm核心功能 npm 常用指令及其作用 執行npm i 發生了什么? 1. 解析命令與參數 2. 檢查依賴文件 3. 依賴版本解析與樹構建 4. 緩存檢查與包下載 5. 解壓包到 node_modules 6. 更新 package-lock.json 7. 處理特殊依賴類型 8. 執行生命周期腳本 9. …

React Native 安卓端 android Image 播放gif webp 動態圖

React Native 安卓端 android Image 播放gif webp 動態圖 RN項目是0.78.2 React是19.0 基本介紹 Image 是 React Native 中用于顯示各種類型圖片的核心組件&#xff0c;支持顯示網絡圖片、靜態資源、本地圖片以及 base64 編碼的圖片。在 Android 端&#xff0c;Image 組件還可…

實時數字人——DH_LIVE

前兩天親手搭建了實時對話數字人VideoChat&#xff0c;今天來搭建下DH_LIVE。 DH_LIVE一個實時數字人解決方案&#xff0c;從輸入文字到數字人對口型說話用時2-3秒。 今天就來實際操作下dh_live的搭建過程。 首先貼上git地址&#xff1a;https://github.com/kleinlee/DH_liv…

AOSP CachedAppOptimizer 凍結方案

背景 Android 一直面臨一個核心難題&#xff1a;如何優化進程對有限系統資源&#xff08;如 CPU、電量&#xff09;的使用&#xff0c;同時保證用戶體驗。 當進程進入后臺后&#xff0c;它們雖不再貢獻用戶體驗&#xff0c;卻仍可能消耗資源。傳統的殺后臺方案雖然節省資源&a…

實體店的小程序轉型之路:擁抱新零售的密碼-中小企實戰運營和營銷工作室博客

實體店的小程序轉型之路&#xff1a;擁抱新零售的密碼-中小企實戰運營和營銷工作室博客 在當今數字化浪潮的沖擊下&#xff0c;實體店面臨著前所未有的挑戰&#xff0c;但小程序的出現為實體店轉型新零售帶來了新的曙光。先來看一組驚人的數據&#xff0c;據相關統計&#xff…

Java求職面試:從Spring Boot到微服務的全面考核

Java求職面試實錄&#xff1a;從Spring Boot到微服務的全面考核 第一輪&#xff1a;基礎技術的考察 場景&#xff1a; 趙大寶走進了一家互聯網大廠的面試間&#xff0c;面試官嚴肅地看著他。 面試官&#xff1a; 趙大寶&#xff0c;你好。我們先從簡單的開始。請你解釋一下J…

記錄一個坑關于STM32 ARM Compiler Version

在用 Keil 進行 STM32 開發的時候&#xff0c;一開始下載&#xff0c;下載的 ARM 編譯器是 Version6&#xff0c;他就不兼容老的代碼&#xff0c;就很抽象。 所以必須要更換編譯器。 可以去官網下載編譯器 Downloads - Arm Developer &#xff0c;也可以自己找資源哈&#xff…

PCIe體系結構學習入門——PCI總線概述(二)PCI總線的橋和配置

這里寫目錄標題 序言存儲器域和 PCI 總線域HOST 主橋PCI 橋和 PCI 設備配置空間PCI 橋PCI 設備配置空間PCI 總線的配置非透明 PCI 橋序言 接續前章內容,本章繼續講述 PCI 總線概述的第二部分——PCI 總線的橋和配置。 如果需要進一步了解前一章節內容,可以訪問:PCIe體系結構…

潯川代碼編輯器v2.0(測試版)更新公告

潯川代碼編輯器v2.0(測試版)更新公告 發布日期&#xff1a;** 2023年4月30日 我們很高興地宣布潯川代碼編輯器v2.0測試版即將上線&#xff01;本次更新帶來了多項功能改進和問題修復&#xff0c;旨在為用戶提供更穩定、更強大的編程體驗。 主要更新內容 1. **Bug修復與穩定性提…

微信小程序 tabbar底部導航欄

官方文檔&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#tabBar 一、常規菜單格式 在app.json 文件中配置&#xff0c;其他關鍵點詳見官方文檔&#xff0c;后續更新不規則圖標的寫法

Spring 中@Autowired,@Resource,@Inject 注解實現原理

使用案例 前置條件&#xff1a; 現在有一個 Vehicle 接口&#xff0c;它有兩個實現類 Bus 和 Car &#xff0c;現在還有一個類 VehicleService 需要注入一個 Vehicle 類型的 Bean&#xff1a; public interface Vehicle {}Component public class Car implements Vehicle {}C…

【Rust結構體】Rust結構體詳解:從基礎到高級應用

?? 歡迎大家來到景天科技苑?? &#x1f388;&#x1f388; 養成好習慣&#xff0c;先贊后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者簡介&#xff1a;景天科技苑 &#x1f3c6;《頭銜》&#xff1a;大廠架構師&#xff0c;華為云開發者社區專家博主&#xff0c;…