当完成渲染流程后,需要finishConcurrentRender提交渲染
1.finishConcurrentRender
该函数 finishConcurrentRender 是React并发渲染流程的最终处理阶段,主要处理六种渲染结果状态:根据并发渲染的结果状态,决定是立即提交、延迟提交还是处理错误
function finishConcurrentRender(root, exitStatus, lanes) {
switch (exitStatus) {
// 异常状态处理
case RootInProgress:
case RootFatalErrored:
throw new Error('Root did not complete. This is a bug in React.');
// 错误重试处理
case RootErrored:
commitRoot(...); // 提交包含错误信息的根节点
break;
// 挂起状态处理
case RootSuspended:
markRootSuspended(root, lanes); // 标记根节点为挂起状态
if (仅包含重试操作) {
const msUntilTimeout = ...; // 计算节流时间
if (需要延迟提交) {
root.timeoutHandle = scheduleTimeout(...); // 设置延迟提交
break;
}
}
commitRoot(...); // 立即提交
break;
// 延迟挂起处理
case RootSuspendedWithDelay:
if (仅过渡操作) {
break; // 过渡操作不提交占位符
}
if (需要JND优化) {
const msUntilTimeout = jnd(...); // 计算可感知差异时间
root.timeoutHandle = scheduleTimeout(...); // 设置优化延迟
break;
}
commitRoot(...); // 提交占位符
break;
// 完成状态处理
case RootCompleted:
commitRoot(...); // 正常提交完成
break;
}
}
graph TD
A[RootInProgress] --> B[抛出异常]
A --> C[RootErrored]
A --> D[RootSuspended]
A --> E[RootSuspendedWithDelay]
A --> F[RootCompleted]
C --> G[立即提交]
D --> H{是否仅重试?}
H -->|是| I[延迟提交]
H -->|否| J[立即提交]
E --> K{是否过渡?}
K -->|是| L[跳过提交]
K -->|否| M[优化延迟]
F --> N[正常提交]
commitRoot 提交入口函数
commitRoot函数是React提交阶段的入口,负责将协调阶段产生的副作用应用到DOM上
该函数的参数:root是Fiber树的根节点,recoverableErrors是可恢复的错误数组,transitions是过渡相关的数组
graph TD
A[开始] --> B[保存当前状态]
B --> C[设置最高优先级]
C --> D[执行实际提交]
D --> E[恢复原始状态]
E --> F[返回null]
function commitRoot(
root: FiberRoot,
recoverableErrors: null | Array<CapturedValue<mixed>>,
transitions: Array<Transition> | null,
) {
// 保存当前更新优先级和过渡状态
const previousUpdateLanePriority = getCurrentUpdatePriority();
const prevTransition = ReactCurrentBatchConfig.transition;
try {
// 重置过渡配置
ReactCurrentBatchConfig.transition = null;
// 设置离散事件优先级(最高优先级)
setCurrentUpdatePriority(DiscreteEventPriority);
// 调用实际提交实现
commitRootImpl(
root,
recoverableErrors,
transitions,
previousUpdateLanePriority,
);
} finally {
// 恢复原始配置
ReactCurrentBatchConfig.transition = prevTransition;
setCurrentUpdatePriority(previousUpdateLanePriority);
}
return null;
}
commitRootImpl
commitRootImpl是提交阶段的核心实现,负责处理副作用、调用生命周期方法以及更新DOM
处理被动效果(passive effects),使用do-while循环调用flushPassiveEffects,直到所有被动效果处理完毕
检查执行上下文,确保当前不在渲染或提交阶段,避免重复操作
如果finishedWork为null,说明没有需要提交的内容,函数直接返回。否则,继续处理
处理回调节点和优先级,清理root的回调相关状态,确保新的回调可以被调度。然后是合并剩余的车道(lanes),考虑并发更新,标记根节点为完成状态
处理被动效果的调度,如果有被动效果存在,安排回调函数在之后处理
检查整个树是否有副作用,分为子树和根节点的效果。如果有,进入提交阶段的不同子阶段:before mutation、mutation、layout
处理完所有效果后,恢复执行上下文和优先级,确保后续操作不受影响。如果没有效果,直接更新root.current并记录时间
最后是处理被动效果的引用,安排后续的清理和调度。检查剩余的工作车道,处理可能的同步更新循环,刷新同步回调,并结束提交阶段的标记
协调阶段完成 → commitRootImpl → 提交到DOM
↓
完成DOM更新/生命周期调用/effects调度
graph TD
A[开始] --> B[清理被动效果]
B --> C[环境检查]
C --> D{是否可提交?}
D -->|否| E[直接返回]
D -->|是| F[提交前准备]
F --> G[Before Mutation]
G --> H[Mutation]
H --> I[Layout]
I --> J[被动效果调度]
J --> K[收尾工作]
function commitRootImpl(...) {
// 阶段1:清理被动效果
do {
flushPassiveEffects();
} while (rootWithPendingPassiveEffects !== null); // 循环直到所有被动effects处理完成
// 阶段2:准备提交环境
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
throw new Error('Should not already be working.'); // 确保不在渲染/提交阶段
}
const finishedWork = root.finishedWork; // 获取已完成的工作树
const lanes = root.finishedLanes; // 关联的优先级通道
// 开发模式调试标记
if (__DEV__ && enableDebugTracing) logCommitStarted(lanes);
if (enableSchedulingProfiler) markCommitStarted(lanes);
// 阶段3:提交前检查
if (finishedWork === null) return null; // 无内容可提交
root.finishedWork = null; // 重置完成状态
root.finishedLanes = NoLanes;
// 阶段4:提交核心逻辑
if (subtreeHasEffects || rootHasEffect) { // 存在需要处理的副作用
const prevTransition = ReactCurrentBatchConfig.transition;
ReactCurrentBatchConfig.transition = null; // 临时禁用过渡
// 子阶段1:Before Mutation(DOM变更前)
const shouldFireAfterActiveInstanceBlur = commitBeforeMutationEffects(...);
// 子阶段2:Mutation(DOM变更)
commitMutationEffects(root, finishedWork, lanes);
resetAfterCommit(root.containerInfo); // 重置宿主环境
// 子阶段3:Layout(布局效果)
root.current = finishedWork; // 切换当前树
commitLayoutEffects(finishedWork, root, lanes);
requestPaint(); // 请求浏览器重绘
}
// 阶段5:被动效果调度
if (rootDoesHavePassiveEffects) { // 存在延迟的被动效果
scheduleCallback(NormalSchedulerPriority, () => {
flushPassiveEffects(); // 异步调度被动effects
return null;
});
}
// 阶段6:收尾工作
ensureRootIsScheduled(root, now()); // 安排后续任务
if (hasUncaughtError) throw firstUncaughtError; // 抛出未捕获错误
flushSyncCallbacks(); // 处理同步回调
}
commitBeforeMutationEffects
该函数主要是处理变更之前的副作用,比如调用getSnapshotBeforeUpdate生命周期方法
函数接收root和firstChild作为参数。root是Fiber树的根节点,firstChild是第一个需要处理的子节点
调用commitBeforeMutationEffects_begin,这个函数会遍历所有子节点,处理带有BeforeMutationMask标志的Fiber节点
提交阶段 → Before Mutation → commitBeforeMutationEffects
↓
处理DOM变更前的副作用(如getSnapshotBeforeUpdate)
export function commitBeforeMutationEffects(
root: FiberRoot,
firstChild: Fiber,
) {
// 设置当前焦点实例句柄(用于DOM变更后恢复焦点)
focusedInstanceHandle = prepareForCommit(root.containerInfo);
// 初始化副作用处理指针
nextEffect = firstChild;
// 开始遍历处理BeforeMutation阶段的副作用
commitBeforeMutationEffects_begin();
// 保存是否需要触发blur事件的标志
const shouldFire = shouldFireAfterActiveInstanceBlur;
// 重置全局状态
shouldFireAfterActiveInstanceBlur = false;
focusedInstanceHandle = null;
return shouldFire; // 返回是否需要触发blur事件
}
commitBeforeMutationEffects_begin
该函数的作用可能是遍历Fiber树,处理所有在DOM变更前需要完成的副作用
graph TD
A[开始] --> B{nextEffect存在?}
B -->|是| C[处理当前Fiber]
C --> D{存在删除操作?}
D -->|是| E[处理删除副作用]
D -->|否| F[处理子节点]
F --> G{子节点需处理?}
G -->|是| H[深度遍历子节点]
G -->|否| I[完成当前节点]
H & I --> B
B -->|否| J[结束]
- nextEffect : 全局遍历指针,指向当前处理的Fiber节点
- subtreeFlags : 记录子树副作用的位字段
function commitBeforeMutationEffects_begin() {
// 开始遍历所有待处理的Fiber节点
while (nextEffect !== null) {
const fiber = nextEffect; // 当前处理的Fiber节点
// 仅当启用事件处理API时执行删除操作
if (enableCreateEventHandleAPI) {
// 处理当前Fiber的删除列表
const deletions = fiber.deletions;
if (deletions !== null) { // 存在待删除的子节点
for (let i = 0; i < deletions.length; i++) {
const deletion = deletions[i];
commitBeforeMutationEffectsDeletion(deletion); // 执行删除前的副作用处理
}
}
}
// 处理子节点
const child = fiber.child;
if (
(fiber.subtreeFlags & BeforeMutationMask) !== NoFlags && // 子树存在待处理副作用
child !== null // 存在子节点
) {
child.return = fiber; // 建立子节点与父节点的关联
nextEffect = child; // 移动指针到子节点
} else {
commitBeforeMutationEffects_complete(); // 完成当前节点的处理
}
}
}
commitMutationEffects
实际调用commitMutationEffectsOnFiber函数
根据fiber里的tag,分别调用commitReconciliationEffects
继而调用commitPlacement
function commitPlacement(finishedWork) {
// ... 处理 DOM 插入/移动逻辑 ...
const parent = getHostParent(finishedWork);
insertOrAppendPlacementNode(finishedWork, parent);
}
commitLayoutEffects
调用commitLayoutEffects_begin函数,该函数在 React 的提交阶段被调用,主要负责协调和处理组件的生命周期钩子(如 componentDidMount、componentDidUpdate)以及 DOM 更新等操作,确保了浏览器完成绘制后同步执行布局相关的副作用操作
commitRoot → commitLayoutEffects → commitLayoutEffects_begin
function commitLayoutEffects_begin(
subtreeRoot: Fiber,
root: FiberRoot,
committedLanes: Lanes
) {
// 遍历逻辑实现...
while (nextEffect !== null) {
// 处理每个节点的 layout effects
commitLayoutMountEffects_complete()
}
}
commitLayoutMountEffects_complete
commitLayoutMountEffects_complete 函数是提交阶段布局子阶段(layout phase)的核心函数之一,主要负责执行DOM插入后的生命周期方法和布局相关副作用
function commitLayoutMountEffects_complete(
root: FiberRoot,
parent: Fiber | null,
finishedWork: Fiber
) {
// ... existing code ...
// 遍历子树执行布局效果
while (current !== null) {
if ((current.flags & LayoutMask) !== NoFlags) {
commitLayoutEffectOnFiber(root, current, fiber, committedLanes);
}
// 处理子节点和兄弟节点
if (current.child !== null) {
current.child.return = current;
current = current.child;
continue;
}
// ... 完成当前节点后的回溯逻辑 ...
}
// ... existing code ...
}
commitLayoutEffects()
├─ commitLayoutEffects_begin() // 初始遍历
└─ commitLayoutMountEffects_complete() // 完整子树处理
commitLayoutEffectOnFiber
commitLayoutEffectOnFiber 函数位于 React 协调器的提交阶段(commit phase),负责处理与布局相关的副作用(layout effects)
function commitLayoutEffectOnFiber(
finishedRoot: FiberRoot,
current: Fiber | null,
finishedWork: Fiber,
committedLanes: Lanes,
): void {
switch (finishedWork.tag) {
case HostRoot: {
// 处理根节点布局效果
if (supportsMutation) {
if (finishedWork.flags & Update) {
const root = finishedWork.stateNode;
commitUpdateQueue(finishedWork, root, null);
}
}
break;
}
case ClassComponent: {
// 处理类组件生命周期
const instance = finishedWork.stateNode;
if (finishedWork.flags & Update) {
if (current === null) {
instance.componentDidMount(); // 挂载后
} else {
instance.componentDidUpdate(); // 更新后
}
}
break;
}
case FunctionComponent: {
// 处理函数组件布局effect
if (finishedWork.flags & Update) {
commitHookEffectListMount(
HookLayout | HookHasEffect,
finishedWork,
);
}
break;
}
case HostComponent: {
// 处理原生DOM组件
const instance = finishedWork.stateNode;
if (finishedWork.flags & Ref) {
commitAttachRef(finishedWork); // 处理ref绑定
}
break;
}
}
}
处理完提交阶段后的副作用后,requestPaint申请浏览器重绘,设置needsPaint = true