一. 前置概要
-
performWorkOnRoot
这是根节点调度的入口函数,负责驱动一次完整的渲染流程。 -
renderRootConcurrent / renderRootSync
根据调度策略,选择并发或同步渲染,内部会循环调用 performUnitOfWork。 -
performUnitOfWork
这是 Fiber 树遍历的核心,每次处理一个 Fiber 节点,并调用 beginWork。 -
beginWork
这里会根据 Fiber 类型(函数组件、类组件、HostComponent 等)生成子 Fiber 节点,递归构建 Fiber 树。
总结:
Fiber 树的构建入口是 performWorkOnRoot,真正的 Fiber 节点构建发生在 beginWork。
performWorkOnRoot → renderRootConcurrent/renderRootSync → performUnitOfWork → beginWork(递归构建子 Fiber)
二. 具体分析
performWorkOnRoot
React Fiber 协调器的核心入口之一,负责在根节点(root)上执行一次完整的渲染(render)和提交(commit)流程。它会根据当前的优先级、调度策略和渲染状态,选择同步或并发的渲染方式,并处理各种异常、挂起(suspend)、错误恢复等复杂场景
源码如下:
export function performWorkOnRoot(
root: FiberRoot,
lanes: Lanes,
forceSync: boolean,
): void {
// 1. 防止嵌套渲染或提交,保证执行上下文正确
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
throw new Error('Should not already be working.');
}
// 2. 性能分析:如有必要,记录上次 yield 的耗时
if (enableProfilerTimer && enableComponentPerformanceTrack) {
if (workInProgressRootRenderLanes !== NoLanes && workInProgress !== null) {
const yieldedFiber = workInProgress;
// 记录让出主线程的耗时和原因
const yieldEndTime = now();
switch (yieldReason) {
case SuspendedOnImmediate:
case SuspendedOnData:
logSuspendedYieldTime(yieldStartTime, yieldEndTime, yieldedFiber);
break;
case SuspendedOnAction:
logActionYieldTime(yieldStartTime, yieldEndTime, yieldedFiber);
break;
default:
logYieldTime(yieldStartTime, yieldEndTime);
}
}
}
// 3. 判断是否启用时间分片(并发渲染),否则走同步渲染
const shouldTimeSlice =
(!forceSync &&
!includesBlockingLane(lanes) &&
!includesExpiredLane(root, lanes)) ||
// prerender 场景下即使是同步优先级也走并发渲染,避免阻塞主线程
checkIfRootIsPrerendering(root, lanes);
// 4. 根据 shouldTimeSlice 选择并发或同步渲染主流程
let exitStatus = shouldTimeSlice
? renderRootConcurrent(root, lanes)
: renderRootSync(root, lanes, true);
let renderWasConcurrent = shouldTimeSlice;
// 5. 渲染主循环,处理一致性校验、错误重试、挂起等特殊情况
do {
if (exitStatus === RootInProgress) {
// 渲染未完成,可能因为 prerender/suspend 等原因需要暂停
if (workInProgressRootIsPrerendering && !shouldTimeSlice) {
// prerender 模式下但未启用时间分片,需标记为挂起
const didAttemptEntireTree = false;
markRootSuspended(root, lanes, NoLane, didAttemptEntireTree);
}
if (enableProfilerTimer && enableComponentPerformanceTrack) {
// 记录 yield 的原因和时间
startYieldTimer(workInProgressSuspendedReason);
}
break;
} else {
let renderEndTime = 0;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
renderEndTime = now();
}
// 5.1 并发渲染下校验外部 store 是否一致,不一致则强制同步重渲染
const finishedWork: Fiber = (root.current.alternate: any);
if (
renderWasConcurrent &&
!isRenderConsistentWithExternalStores(finishedWork)
) {
if (enableProfilerTimer && enableComponentPerformanceTrack) {
setCurrentTrackFromLanes(lanes);
logInconsistentRender(renderStartTime, renderEndTime);
finalizeRender(lanes, renderEndTime);
}
// 外部 store 发生变更,强制同步重渲染
exitStatus = renderRootSync(root, lanes, false);
renderWasConcurrent = false;
continue;
}
// 5.2 错误处理:如果渲染出错,尝试同步重试
if (
(disableLegacyMode || root.tag !== LegacyRoot) &&
exitStatus === RootErrored
) {
const lanesThatJustErrored = lanes;
const errorRetryLanes = getLanesToRetrySynchronouslyOnError(
root,
lanesThatJustErrored,
);
if (errorRetryLanes !== NoLanes) {
if (enableProfilerTimer && enableComponentPerformanceTrack) {
setCurrentTrackFromLanes(lanes);
logErroredRenderPhase(renderStartTime, renderEndTime, lanes);
finalizeRender(lanes, renderEndTime);
}
lanes = errorRetryLanes;
exitStatus = recoverFromConcurrentError(
root,
lanesThatJustErrored,
errorRetryLanes,
);
renderWasConcurrent = false;
// 如果重试后不再报错,则重新进入主循环
if (exitStatus !== RootErrored) {
continue;
} else {
if (enableProfilerTimer && enableComponentPerformanceTrack) {
renderEndTime = now();
}
}
}
}
// 5.3 致命错误,直接标记为挂起
if (exitStatus === RootFatalErrored) {
if (enableProfilerTimer && enableComponentPerformanceTrack) {
setCurrentTrackFromLanes(lanes);
logErroredRenderPhase(renderStartTime, renderEndTime, lanes);
finalizeRender(lanes, renderEndTime);
}
prepareFreshStack(root, NoLanes);
const didAttemptEntireTree = true;
markRootSuspended(root, lanes, NoLane, didAttemptEntireTree);
break;
}
// 5.4 渲染完成,进入提交阶段
finishConcurrentRender(
root,
exitStatus,
finishedWork,
lanes,
renderEndTime,
);
}
break;
} while (true);
// 6. 确保根节点后续任务被调度(如有未完成的任务会继续调度)
ensureRootIsScheduled(root);
}
这里主要关注的点是
// 4. 根据 shouldTimeSlice 选择并发或同步渲染主流程
let exitStatus = shouldTimeSlice ? renderRootConcurrent(root, lanes) : renderRootSync(root, lanes, true);
同步模式调用renderRootSync
是 React Fiber 同步渲染的主流程函数。它的作用是在同步模式下推进 Fiber 树的渲染,确保所有工作在一次主线程任务内完成。函数首先保存当前的执行上下文,并切换到渲染上下文,然后设置当前的 Dispatcher 和异步 Dispatcher,保证 hooks 和调度行为正确。
接下来,如果当前的根节点或优先级(lanes)发生变化,会重置 Fiber 栈,准备新的渲染环境,并在开发者工具启用时处理更新追踪相关的数据结构。这一步确保每次渲染都能从正确的状态开始,避免数据错乱。
主循环部分,renderRootSync 会检查是否有挂起(如 Suspense、数据请求等)。在同步渲染下,如果遇到挂起,不会让出主线程,而是立即展开 Fiber 栈,触发降级 UI 或错误边界。如果遇到 hydration(服务端渲染的水合),会中断当前渲染,切换到 hydration 相关的 lane。对于其他挂起类型,会根据情况判断是否需要切换到预渲染模式(prerendering),如果需要则退出循环,等待并发渲染恢复。
如果没有挂起,函数会调用 workLoopSync,以同步方式推进所有 Fiber 节点的 beginWork 和 completeWork,直到整棵树渲染完成或再次遇到异常。异常会被捕获并通过 handleThrow 处理,保证渲染流程的健壮性。
渲染结束后,函数会重置上下文依赖、恢复上下文和 Dispatcher,并在启用调度分析器时记录渲染停止。最后,如果 Fiber 树还有未完成的工作,说明渲染被挂起;否则会清理相关状态,处理并发更新队列,并返回最终的退出状态。这样保证了同步渲染的高效性和一致性,同时为后续的提交(commit)阶段做好准备
并发模式调用renderRootConcurrent
源码中有几个相对比较关键的变量及概念
- lanes:当前正在调度的 更新优先级 Lane(Lane 模型) ,React 用 Lane 代替之前的 Priority 来管理更新优先级。
- fiber栈: React 通过 Fiber 节点 和 调度器 实现 Fiber 栈,它不是独立的数据结构,而是 基于 Fiber 树的一种任务调度机制,类似于树的遍历隐式维护了一个栈的效果
源码如下:
/**
* 并发渲染根Fiber节点
* @param root 当前Fiber根节点
* @param lanes 当前渲染的优先级通道
* @returns 返回渲染状态(进行中/已完成等)
*/
function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
// 保存当前执行上下文
const prevExecutionContext = executionContext;
// 设置当前执行上下文为渲染模式
executionContext |= RenderContext;
// 切换Dispatcher,设置当前容器的context
const prevDispatcher = pushDispatcher(root.containerInfo);
// 切换异步Dispatcher
const prevAsyncDispatcher = pushAsyncDispatcher();
/**
* 如果根节点或优先级发生变化,重置Fiber栈,否则继续上次未完成的工作
*/
if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
if (enableUpdaterTracking) {
if (isDevToolsPresent) {
const memoizedUpdaters = root.memoizedUpdaters;
if (memoizedUpdaters.size > 0) {
// 恢复上次未完成的updaters
restorePendingUpdaters(root, workInProgressRootRenderLanes);
memoizedUpdaters.clear();
}
// 将本次调度的Fiber从Map移动到Set,便于区分本次和未来的更新
movePendingFibersToMemoized(root, lanes);
}
}
// 获取本次调度相关的transition
workInProgressTransitions = getTransitionsForLanes(root, lanes);
// 重置渲染计时器
resetRenderTimer();
// 构建新的Fiber栈
prepareFreshStack(root, lanes);
} else {
// 继续上次未完成的工作
// 如果之前处于预渲染模式,检查是否有新数据
workInProgressRootIsPrerendering = checkIfRootIsPrerendering(root, lanes);
}
// 调度分析工具标记渲染开始
if (enableSchedulingProfiler) {
markRenderStarted(lanes);
}
/**
* 主循环,处理Fiber树
* 使用标签循环以便在挂起时可以跳出多层循环
*/
outer: do {
try {
/**
* 如果当前work loop处于挂起状态,处理挂起逻辑
*/
if (
workInProgressSuspendedReason !== NotSuspended &&
workInProgress !== null
) {
// 当前单元Fiber
const unitOfWork = workInProgress;
// 挂起时抛出的值(如Promise)
const thrownValue = workInProgressThrownValue;
// 根据挂起原因处理
resumeOrUnwind: switch (workInProgressSuspendedReason) {
case SuspendedOnError: {
// 发生错误,重置挂起状态,展开栈
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
throwAndUnwindWorkLoop(
root,
unitOfWork,
thrownValue,
SuspendedOnError,
);
break;
}
case SuspendedOnData:
case SuspendedOnAction: {
// 挂起在数据Promise上
const thenable: Thenable<mixed> = (thrownValue: any);
if (isThenableResolved(thenable)) {
// 数据已就绪,重试渲染
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
replaySuspendedUnitOfWork(unitOfWork);
break;
}
// 数据未就绪,注册回调,等待数据
const onResolution = () => {
if (
(workInProgressSuspendedReason === SuspendedOnData ||
workInProgressSuspendedReason === SuspendedOnAction) &&
workInProgressRoot === root
) {
workInProgressSuspendedReason = SuspendedAndReadyToContinue;
}
ensureRootIsScheduled(root);
};
thenable.then(onResolution, onResolution);
break outer; // 跳出外层循环
}
case SuspendedOnImmediate: {
// 立即挂起,切换为"准备继续"状态,等待主线程机会
workInProgressSuspendedReason = SuspendedAndReadyToContinue;
break outer; // 跳出外层循环
}
case SuspendedOnInstance: {
// 资源实例挂起,切换为"实例准备继续"状态
workInProgressSuspendedReason =
SuspendedOnInstanceAndReadyToContinue;
break outer; // 跳出外层循环
}
case SuspendedAndReadyToContinue: {
// 数据已准备好,重试渲染,否则展开栈
const thenable: Thenable<mixed> = (thrownValue: any);
if (isThenableResolved(thenable)) {
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
replaySuspendedUnitOfWork(unitOfWork);
} else {
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
throwAndUnwindWorkLoop(
root,
unitOfWork,
thrownValue,
SuspendedAndReadyToContinue,
);
}
break;
}
case SuspendedOnInstanceAndReadyToContinue: {
// 检查资源是否已准备好
let resource: null | Resource = null;
switch (workInProgress.tag) {
case HostHoistable: {
resource = workInProgress.memoizedState;
}
// intentional fallthrough
case HostComponent:
case HostSingleton: {
const hostFiber = workInProgress;
const type = hostFiber.type;
const props = hostFiber.pendingProps;
const isReady = resource
? preloadResource(resource)
: preloadInstance(hostFiber.stateNode, type, props);
if (isReady) {
// 资源已准备好,继续work loop
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
const sibling = hostFiber.sibling;
if (sibling !== null) {
workInProgress = sibling;
} else {
const returnFiber = hostFiber.return;
if (returnFiber !== null) {
workInProgress = returnFiber;
completeUnitOfWork(returnFiber);
} else {
workInProgress = null;
}
}
break resumeOrUnwind; // 跳出switch
}
break;
}
default: {
// 非预期类型,开发环境下报错
if (__DEV__) {
console.error(
'Unexpected type of fiber triggered a suspensey commit. ' +
'This is a bug in React.',
);
}
break;
}
}
// 资源未准备好,展开栈
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
throwAndUnwindWorkLoop(
root,
unitOfWork,
thrownValue,
SuspendedOnInstanceAndReadyToContinue,
);
break;
}
case SuspendedOnDeprecatedThrowPromise: {
// 兼容旧的throw promise模式,直接展开栈
workInProgressSuspendedReason = NotSuspended;
workInProgressThrownValue = null;
throwAndUnwindWorkLoop(
root,
unitOfWork,
thrownValue,
SuspendedOnDeprecatedThrowPromise,
);
break;
}
case SuspendedOnHydration: {
// 水合挂起,重置Fiber栈,退出循环
resetWorkInProgressStack();
workInProgressRootExitStatus = RootSuspendedAtTheShell;
break outer; // 跳出外层循环
}
default: {
throw new Error(
'Unexpected SuspendedReason. This is a bug in React.',
);
}
}
}
/**
* 如果在act测试环境下,不判断shouldYield,直接同步work loop
*/
if (__DEV__ && ReactSharedInternals.actQueue !== null) {
workLoopSync();
} else if (enableThrottledScheduling) {
// 启用节流调度,分帧work loop
workLoopConcurrent(includesNonIdleWork(lanes));
} else {
// 默认并发work loop,遇到shouldYield时让出主线程
workLoopConcurrentByScheduler();
}
break; // 正常完成work loop,跳出switch
} catch (thrownValue) {
// 捕获异常,处理错误或挂起
handleThrow(root, thrownValue);
}
} while (true); // 持续循环直到完成或挂起
// 重置context依赖
resetContextDependencies();
// 恢复Dispatcher和执行上下文
popDispatcher(prevDispatcher);
popAsyncDispatcher(prevAsyncDispatcher);
executionContext = prevExecutionContext;
/**
* 判断Fiber树是否完成
*/
if (workInProgress !== null) {
// 还有未完成的工作,返回进行中状态
if (enableSchedulingProfiler) {
markRenderYielded();
}
return RootInProgress;
} else {
// 树已完成,清理全局状态
if (enableSchedulingProfiler) {
markRenderStopped();
}
workInProgressRoot = null;
workInProgressRootRenderLanes = NoLanes;
// 渲染阶段完成,可以安全处理并发更新队列
finishQueueingConcurrentUpdates();
// 返回最终退出状态
return workInProgressRootExitStatus;
}
}
是 React Fiber 并发渲染的核心函数。它负责以并发模式(即可中断、可恢复的方式)对 Fiber 树进行渲染。函数首先保存当前的执行上下文,并设置为渲染上下文,然后初始化调度器和异步调度器。
接下来,函数会判断当前的 root 或 lanes(优先级)是否发生变化。如果发生变化,则重置 Fiber 栈,准备一次全新的渲染;否则,继续上一次未完成的渲染任务(对挂起的任务做了细致的恢复处理)。此处还涉及开发者工具相关的 updater 跟踪和事务管理,确保调试信息的准确性。
在主循环中,函数会根据当前的挂起(suspended)状态,决定是回放(replay)被挂起的单元,还是展开(unwind)Fiber 栈。对于不同的挂起原因(如数据请求、错误、实例未就绪等),采取不同的恢复或中断策略。例如,如果数据已就绪,会尝试重新渲染;如果还未就绪,则挂起等待,并通过 thenable 的回调确保后续能恢复渲染。
渲染主循环采用 do-while 结构,支持异常捕获和恢复。渲染过程中会根据环境选择同步或并发的工作循环(workLoopSync、workLoopConcurrent、workLoopConcurrentByScheduler)。渲染结束后,重置上下文和调度器,并根据是否还有未完成的工作返回不同的状态。
在这里主要关注的函数是workLoopConcurrentByScheduler,它是构建的默认调度
workLoopConcurrentByScheduler
function workLoopConcurrentByScheduler() {
// Perform work until Scheduler asks us to yield
while (workInProgress !== null && !shouldYield()) {
// $FlowFixMe[incompatible-call] flow doesn't know that shouldYield() is side-effect free
performUnitOfWork(workInProgress);
}
}
每处理一部分 Fiber 节点后,通过shouldYield()判断是否需要让出主线程。如果需要,就暂停渲染,等待浏览器空闲时再继续。
这种方式可以让 React 渲染过程与浏览器的高优先级任务(如输入、动画)协同,不会长时间阻塞主线程。
进一步的,下面进入performUnitOfWork
performUnitOfWork
function performUnitOfWork(unitOfWork: Fiber): void {
// 当前已刷新的Fiber状态存储在alternate属性中
// 理想情况下不应该依赖这个属性,但在这里使用它可以避免在工作进行中需要额外的字段
const current = unitOfWork.alternate;
let next; // 下一个要处理的工作单元
// 如果启用了性能分析计时器且当前Fiber处于性能分析模式
if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) {
// 开始记录当前Fiber的性能分析计时器
startProfilerTimer(unitOfWork);
// 在开发环境下使用runWithFiberInDEV包装beginWork调用
// 这可能是为了在开发模式下提供额外的调试信息或错误检查
if (__DEV__) {
next = runWithFiberInDEV(
unitOfWork,
beginWork, // 开始处理当前Fiber的工作
current, // 当前已刷新的Fiber
unitOfWork, // 正在处理的工作单元
entangledRenderLanes, // 相关的渲染通道
);
} else {
// 生产环境下直接调用beginWork
next = beginWork(current, unitOfWork, entangledRenderLanes);
}
// 停止性能分析计时器并记录持续时间
stopProfilerTimerIfRunningAndRecordDuration(unitOfWork);
} else {
// 如果没有启用性能分析计时器
if (__DEV__) {
// 开发环境下同样使用runWithFiberInDEV包装beginWork调用
next = runWithFiberInDEV(
unitOfWork,
beginWork,
current,
unitOfWork,
entangledRenderLanes,
);
} else {
// 生产环境下直接调用beginWork
next = beginWork(current, unitOfWork, entangledRenderLanes);
}
}
// 将当前Fiber的memoizedProps更新为pendingProps
// 这表示当前Fiber的props已经被处理并可以用于后续渲染
unitOfWork.memoizedProps = unitOfWork.pendingProps;
// 如果next为null,表示当前Fiber没有产生新的工作单元
if (next === null) {
// 完成当前Fiber的工作
completeUnitOfWork(unitOfWork);
} else {
// 否则,将workInProgress设置为下一个要处理的工作单元
// 这将使得后续的处理继续在这个新的Fiber上进行
workInProgress = next;
}
}
performUnitOfWork函数,用于执行单个Fiber单元的工作并决定下一步要处理的Fiber
-
参数
unitOfWork:当前要处理的Fiber节点 -
返回
void:通过修改全局变量workInProgress来驱动工作循环 -
通过
beginWork和completeUnitOfWork的配合实现深度优先遍历 -
这个函数是Fiber架构工作循环的核心,实现了"处理当前节点->获取下一个节点"的流程
-
处理当前节点的收尾工作,比如创建 DOM 节点、收集副作用(如插入、更新、删除等)。
这里重点要注意的是:
- 递归地处理兄弟节点(sibling) ,即横向遍历。
- 当没有兄弟节点时,回溯到父节点(return) ,即向上返回,继续完成父节点的收尾工作。
completeUnitOfWork是“离开”一个节点的地方,它负责完成当前节点并转向兄弟节点或回溯到父节点
下面看看beginWork是如何对每一个节点做处理的
beginWork
beginWork
function beginWork(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
): Fiber | null {
// 开发环境下,如果需要重新挂载(如热更新),则创建新 fiber 并 remount
if (__DEV__) {
if (workInProgress._debugNeedsRemount && current !== null) {
// 重新挂载 fiber,通常用于调试或热重载
const copiedFiber = createFiberFromTypeAndProps(
workInProgress.type,
workInProgress.key,
workInProgress.pendingProps,
workInProgress._debugOwner || null,
workInProgress.mode,
workInProgress.lanes,
);
copiedFiber._debugStack = workInProgress._debugStack;
copiedFiber._debugTask = workInProgress._debugTask;
return remountFiber(current, workInProgress, copiedFiber);
}
}
// 判断是否是更新流程
if (current !== null) {
const oldProps = current.memoizedProps;
const newProps = workInProgress.pendingProps;
// 如果 props、context 发生变化,或类型变了(如热更新),则标记需要更新
if (
oldProps !== newProps ||
hasLegacyContextChanged() ||
(__DEV__ ? workInProgress.type !== current.type : false)
) {
didReceiveUpdate = true;
} else {
// 否则检查是否有调度的更新或 context 变化
const hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(
current,
renderLanes,
);
if (
!hasScheduledUpdateOrContext &&
// 错误边界或 suspense 的二次渲染也要特殊处理
(workInProgress.flags & DidCapture) === NoFlags
) {
// 没有更新,直接 bailout,跳过本节点
didReceiveUpdate = false;
return attemptEarlyBailoutIfNoScheduledUpdate(
current,
workInProgress,
renderLanes,
);
}
// 兼容 legacy suspense 的特殊处理
if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {
didReceiveUpdate = true;
} else {
didReceiveUpdate = false;
}
}
} else {
// 首次挂载流程
didReceiveUpdate = false;
// SSR hydration 场景下,处理多分支子节点的 id 生成
if (getIsHydrating() && isForkedChild(workInProgress)) {
const slotIndex = workInProgress.index;
const numberOfForks = getForksAtLevel(workInProgress);
pushTreeId(workInProgress, numberOfForks, slotIndex);
}
}
// 进入 begin 阶段前,清空本 fiber 的 lanes(优先级)
workInProgress.lanes = NoLanes;
// 根据 fiber 的 tag 类型,分发到不同的处理函数
switch (workInProgress.tag) {
case LazyComponent: {
// 懒加载组件
const elementType = workInProgress.elementType;
return mountLazyComponent(
current,
workInProgress,
elementType,
renderLanes,
);
}
case FunctionComponent: {
// 函数组件
const Component = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
const resolvedProps =
disableDefaultPropsExceptForClasses ||
workInProgress.elementType === Component
? unresolvedProps
: resolveDefaultPropsOnNonClassComponent(Component, unresolvedProps);
return updateFunctionComponent(
current,
workInProgress,
Component,
resolvedProps,
renderLanes,
);
}
case ClassComponent: {
// 类组件
const Component = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
const resolvedProps = resolveClassComponentProps(
Component,
unresolvedProps,
workInProgress.elementType === Component,
);
return updateClassComponent(
current,
workInProgress,
Component,
resolvedProps,
renderLanes,
);
}
case HostRoot:
// 根节点
return updateHostRoot(current, workInProgress, renderLanes);
case HostHoistable:
// 可提升的宿主节点
if (supportsResources) {
return updateHostHoistable(current, workInProgress, renderLanes);
}
// fall through
case HostSingleton:
// 单例宿主节点
if (supportsSingletons) {
return updateHostSingleton(current, workInProgress, renderLanes);
}
// fall through
case HostComponent:
// 普通宿主节点(如 div、span)
return updateHostComponent(current, workInProgress, renderLanes);
case HostText:
// 文本节点
return updateHostText(current, workInProgress);
case SuspenseComponent:
// Suspense 边界
return updateSuspenseComponent(current, workInProgress, renderLanes);
case HostPortal:
// Portal 节点
return updatePortalComponent(current, workInProgress, renderLanes);
case ForwardRef: {
// forwardRef 组件
const type = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
const resolvedProps =
disableDefaultPropsExceptForClasses ||
workInProgress.elementType === type
? unresolvedProps
: resolveDefaultPropsOnNonClassComponent(type, unresolvedProps);
return updateForwardRef(
current,
workInProgress,
type,
resolvedProps,
renderLanes,
);
}
case Fragment:
// Fragment 片段
return updateFragment(current, workInProgress, renderLanes);
case Mode:
// Mode 组件
return updateMode(current, workInProgress, renderLanes);
case Profiler:
// Profiler 组件
return updateProfiler(current, workInProgress, renderLanes);
case ContextProvider:
// Context Provider
return updateContextProvider(current, workInProgress, renderLanes);
case ContextConsumer:
// Context Consumer
return updateContextConsumer(current, workInProgress, renderLanes);
case MemoComponent: {
// React.memo 组件
const type = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
// 先解析外层 defaultProps,再解析内层
let resolvedProps = disableDefaultPropsExceptForClasses
? unresolvedProps
: resolveDefaultPropsOnNonClassComponent(type, unresolvedProps);
resolvedProps = disableDefaultPropsExceptForClasses
? resolvedProps
: resolveDefaultPropsOnNonClassComponent(type.type, resolvedProps);
return updateMemoComponent(
current,
workInProgress,
type,
resolvedProps,
renderLanes,
);
}
case SimpleMemoComponent: {
// 简单 memo 组件
return updateSimpleMemoComponent(
current,
workInProgress,
workInProgress.type,
workInProgress.pendingProps,
renderLanes,
);
}
case IncompleteClassComponent: {
// 挂起的类组件(legacy 模式)
if (disableLegacyMode) {
break;
}
const Component = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
const resolvedProps = resolveClassComponentProps(
Component,
unresolvedProps,
workInProgress.elementType === Component,
);
return mountIncompleteClassComponent(
current,
workInProgress,
Component,
resolvedProps,
renderLanes,
);
}
case IncompleteFunctionComponent: {
// 挂起的函数组件(legacy 模式)
if (disableLegacyMode) {
break;
}
const Component = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
const resolvedProps = resolveClassComponentProps(
Component,
unresolvedProps,
workInProgress.elementType === Component,
);
return mountIncompleteFunctionComponent(
current,
workInProgress,
Component,
resolvedProps,
renderLanes,
);
}
case SuspenseListComponent: {
// SuspenseList 组件
return updateSuspenseListComponent(current, workInProgress, renderLanes);
}
case ScopeComponent: {
// Scope 组件
if (enableScopeAPI) {
return updateScopeComponent(current, workInProgress, renderLanes);
}
break;
}
case ActivityComponent: {
// Activity 组件
return updateActivityComponent(current, workInProgress, renderLanes);
}
case OffscreenComponent: {
// Offscreen 组件
return updateOffscreenComponent(
current,
workInProgress,
renderLanes,
workInProgress.pendingProps,
);
}
case LegacyHiddenComponent: {
// 隐藏组件(legacy 模式)
if (enableLegacyHidden) {
return updateLegacyHiddenComponent(
current,
workInProgress,
renderLanes,
);
}
break;
}
case CacheComponent: {
// Cache 组件
return updateCacheComponent(current, workInProgress, renderLanes);
}
case TracingMarkerComponent: {
// TracingMarker 组件
if (enableTransitionTracing) {
return updateTracingMarkerComponent(
current,
workInProgress,
renderLanes,
);
}
break;
}
case ViewTransitionComponent: {
// ViewTransition 组件
if (enableViewTransition) {
return updateViewTransition(current, workInProgress, renderLanes);
}
break;
}
case Throw: {
// 调和阶段抛出的异常,直接抛出
throw workInProgress.pendingProps;
}
}
// 未知 tag,抛出错误
throw new Error(
`Unknown unit of work tag (${workInProgress.tag}). This error is likely caused by a bug in ` +
'React. Please file an issue.',
);
}
这里引用一张kasong的图
来源网址: react.iamkasong.com/process/beg…
completeUnitOfWork
function completeUnitOfWork(unitOfWork: Fiber): void {
// Attempt to complete the current unit of work, then move to the next
// sibling. If there are no more siblings, return to the parent fiber.
let completedWork: Fiber = unitOfWork;
do {
if ((completedWork.flags & Incomplete) !== NoFlags) {
// This fiber did not complete, because one of its children did not
// complete. Switch to unwinding the stack instead of completing it.
//
// The reason "unwind" and "complete" is interleaved is because when
// something suspends, we continue rendering the siblings even though
// they will be replaced by a fallback.
const skipSiblings = workInProgressRootDidSkipSuspendedSiblings;
unwindUnitOfWork(completedWork, skipSiblings);
return;
}
// The current, flushed, state of this fiber is the alternate. Ideally
// nothing should rely on this, but relying on it here means that we don't
// need an additional field on the work in progress.
const current = completedWork.alternate;
const returnFiber = completedWork.return;
let next;
startProfilerTimer(completedWork);
if (__DEV__) {
next = runWithFiberInDEV(
completedWork,
completeWork,
current,
completedWork,
entangledRenderLanes,
);
} else {
next = completeWork(current, completedWork, entangledRenderLanes);
}
if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
// Update render duration assuming we didn't error.
stopProfilerTimerIfRunningAndRecordIncompleteDuration(completedWork);
}
if (next !== null) {
// Completing this fiber spawned new work. Work on that next.
workInProgress = next;
return;
}
const siblingFiber = completedWork.sibling;
if (siblingFiber !== null) {
// If there is more work to do in this returnFiber, do that next.
workInProgress = siblingFiber;
return;
}
// Otherwise, return to the parent
// $FlowFixMe[incompatible-type] we bail out when we get a null
completedWork = returnFiber;
// Update the next thing we're working on in case something throws.
workInProgress = completedWork;
} while (completedWork !== null);
// We've reached the root.
if (workInProgressRootExitStatus === RootInProgress) {
workInProgressRootExitStatus = RootCompleted;
}
}
completeUnitOfWork 函数的主要职责是完成当前的工作单元(unitOfWork),即一个 Fiber 节点,然后根据情况移动到下一个兄弟节点或返回到父节点,直到完成整个工作循环。如果在完成过程中发现某个子节点未完成,函数会切换到展开(unwind)操作,而不是继续完成当前节点。
关键点解析
1. 检查是否完成:
- 使用
completedWork.flags & Incomplete检查当前Fiber是否标记为未完成。如果是,调用unwindUnitOfWork进行展开操作,并结束当前函数。
2. 获取相关 Fiber:
-
current: 当前Fiber的备选(alternate)状态,用于在开发模式下进行比较或恢复。 -
returnFiber: 当前Fiber的父节点,用于在完成当前节点后返回到父节点继续处理。
3. 执行 completeWork :
-
根据是否在开发模式 (
__DEV__),调用completeWork函数完成当前Fiber的工作。 -
在开发模式下,
runWithFiberInDEV用于包装completeWork,可能用于调试或性能分析。 -
在生产模式下,直接调用
completeWork。
4. 性能分析:
- 使用
startProfilerTimer和stopProfilerTimerIfRunningAndRecordIncompleteDuration进行性能计时,记录渲染时间,尤其是在启用了性能分析 (enableProfilerTimer) 且当前Fiber处于ProfileMode时。
5. 处理新生成的工作:
- 如果
completeWork返回了一个新的next工作单元,将workInProgress设置为next,并结束当前函数,继续处理新的工作。
6. 处理兄弟节点和父节点:
-
如果存在兄弟节点 (
siblingFiber),将workInProgress设置为兄弟节点,继续处理兄弟节点。 -
如果没有兄弟节点,将
completedWork设置为其父节点 (returnFiber),并将workInProgress更新为父节点,继续向上处理。
7. 完成根节点:
- 当循环结束时,表示已经处理到根节点。如果根的工作进度状态是
RootInProgress,将其设置为RootCompleted,表示整个工作循环已完成。
总结
completeUnitOfWork 是 React 渲染过程中负责完成单个 Fiber 节点工作的重要函数。它确保每个节点在其子节点完成之后被正确处理,并根据需要移动到兄弟节点或父节点,以完成整个渲染树的遍历。这一过程对于 React 的协调(Reconciliation)算法至关重要,确保高效的更新和渲染。