React中BeginWork和CompleteWork核心解析
一、前置认知
beginWork 和 completeWork 是 React 调和阶段(Reconciliation) 的两大核心工作单元,基于Fiber架构深度优先遍历执行,共同完成[Fiber树构建/更新、Diff算法执行、DOM节点生成、副作用收集]的核心逻辑,为提交阶段提供可执行的指令与依赖。
- 调和阶段 :属于React渲染的可中断、可恢复阶段(由Scheduler调度),只计算更新结果,不操作实际的DOM元素。
- Fiber 遍历规则:先向下执行 beginWork(递)→ 叶子节点后向上执行completeWork(归),单节点遍历完成 = beginWork 执行完毕 + completeWork 执行完毕。
二、beginWork 核心解析
-
核心职责(Fiber 构建 / 更新 + Diff 核心)
beginWork是[递]阶段的核心方法,从根Fiber开始向下遍历,为每个Fiber节点执行创建、更新逻辑。核心做以下4件事:
- Fiber节点创建/复用: 根据当前组件类型(类组件、函数组件、原生DOM),创建新的Fiber或复用已有Fiber(首屏渲染创建,更新阶段则复用);
- Diff算法核心执行 :更新阶段对比「当前 Fiber」和「新虚拟 DOM(pending)」,计算出节点的增 / 删 / 改差异,生成待更新的子 Fiber 节点;
- 子Fiber树构建:为当前 Fiber 生成 / 更新子 Fiber 节点,建立 Fiber 树的父子关联,为后续遍历做准备;
- 优先级判断:结合 Scheduler 优先级机制,判断当前 Fiber 节点的更新是否需要中断,保证高优先级任务(如用户交互)优先执行。
-
核心执行逻辑(分首屏 / 更新阶段)
beginWork 会根据当前 Fiber 树的状态(首屏渲染 / 更新)走不同逻辑,核心是区分首次构建和 Diff 更新,避免无意义的计算:
- 首屏渲染(mount):无旧 Fiber 节点,直接根据虚拟 DOM 创建全新的 Fiber 节点,设置节点类型、属性、子节点等信息;
- 更新阶段(update):存在旧 Fiber 节点,执行Diff 算法(组件级 Diff + 元素级 Diff),复用可复用的旧 Fiber,标记需要删除 / 更新的节点,创建新增节点的 Fiber。
三、completeWork 核心解析
-
核心职责(DOM 生成 + 副作用收集 + 属性处理)
completeWork是「归阶段」的核心方法,从 Fiber 树的叶子节点开始向上遍历,为每个 Fiber 节点执行收尾工作 **,核心做 4 件事:
- 真实 DOM 节点生成 / 挂载:仅针对原生 DOM 类型 Fiber(如 div/span),创建真实 DOM 元素,设置节点属性(className/style/attr 等),并将子 DOM 节点挂载到父 DOM 上;
- 组件属性 / 上下文处理:处理类组件的 props 透传、上下文(Context)的传递与更新,保证组件层级的属性一致性;
- 副作用收集:将当前 Fiber 节点的更新操作(如 DOM 增删改、生命周期执行、useEffect 回调)标记为副作用(Effect),并加入到全局副作用队列中,供提交阶段执行;
- Fiber 节点收尾:完善 Fiber 节点的附加信息,建立 Fiber 与真实 DOM 的映射关系(stateNode 属性),为后续更新和查找提供依据。
-
关键特性
- 仅原生 DOM Fiber会创建真实 DOM,组件类型 Fiber(类 / 函数)不直接生成 DOM,仅做逻辑处理;
- 副作用收集是提交阶段执行真实操作的基础,调和阶段不执行任何副作用,仅标记;
- 向上遍历过程中,会将子 Fiber 的副作用合并到父 Fiber,最终根 Fiber 持有整个应用的所有副作用,方便提交阶段统一处理。
四、调和过程(beginWork + completeWork)伪代码
js
/**
* React 调和阶段核心遍历方法(深度优先)
* @param {Fiber} currentFiber - 旧Fiber节点(更新阶段)/null(首屏渲染)
* @param {VNode} pendingVNode - 新虚拟DOM节点
* @param {number} expirationTime - 任务过期时间(Scheduler 优先级)
* @returns {Fiber} 处理后的新Fiber节点
*/
function reconcileFiber(currentFiber, pendingVNode, expirationTime) {
// 1. 执行 beginWork:递阶段 - 构建/更新Fiber + Diff逻辑
const nextFiber = beginWork(currentFiber, pendingVNode, expirationTime);
// 2. 深度优先遍历:若有子Fiber,递归处理子节点(继续递阶段)
if (nextFiber.child) {
reconcileFiber(null, nextFiber.child.pendingVNode, expirationTime);
}
// 3. 执行 completeWork:归阶段 - 生成DOM + 收集副作用
completeWork(nextFiber);
return nextFiber;
}
/**
* beginWork 核心方法:递阶段 - Fiber构建/Diff/子树生成
* @param {Fiber} current - 旧Fiber(update)/null(mount)
* @param {VNode} vnode - 新虚拟DOM
* @param {number} expirationTime - 优先级过期时间
* @returns {Fiber} 新/更新后的Fiber节点
*/
function beginWork(current, vnode, expirationTime) {
let nextFiber;
const { type, props } = vnode;
// 核心职责1:判断更新类型 - 首屏(mount) / 更新(update)
const isMount = !current;
if (isMount) {
// 首屏渲染:核心职责2 - 创建全新Fiber节点
nextFiber = createFiber(vnode, expirationTime);
} else {
// 更新阶段:核心职责3 - 执行Diff算法,复用/更新旧Fiber
nextFiber = reconcileUpdate(current, vnode, expirationTime);
}
// 核心职责4:构建子Fiber树 - 生成子节点Fiber,建立父子关联
nextFiber.child = createChildFibers(nextFiber, props.children, expirationTime);
// 核心职责5:优先级判断 - 若有更高优先级任务,标记中断
if (shouldYield(expirationTime)) {
markWorkInProgress(nextFiber); // 标记为进行中,后续可恢复
}
return nextFiber;
}
/**
* completeWork 核心方法:归阶段 - DOM生成/副作用收集/属性处理
* @param {Fiber} fiber - 已完成beginWork的Fiber节点
*/
function completeWork(fiber) {
const { type, props, stateNode } = fiber;
const isHostComponent = isHostDOMType(type); // 是否为原生DOM组件(div/span等)
// 核心职责1:原生DOM组件 - 生成/更新真实DOM节点
if (isHostComponent) {
if (!stateNode) {
// 首屏:创建真实DOM,挂载到Fiber的stateNode(Fiber-DOM映射)
fiber.stateNode = createDOMElement(type, props);
} else {
// 更新:执行DOM属性Diff,更新已有DOM(避免全量替换)
updateDOMAttributes(stateNode, props);
}
// 核心职责2:将子DOM节点挂载到当前父DOM(归阶段向上,子DOM已生成)
appendChildDOM(fiber.stateNode, fiber.child?.stateNode);
}
// 核心职责3:处理组件上下文/属性透传(类组件/Context)
propagateContext(fiber);
resolveProps(fiber);
// 核心职责4:收集副作用 - 根据Fiber状态标记对应的Effect(DOM增/删/改/生命周期等)
if (hasSideEffect(fiber)) {
collectEffect(fiber, fiber.effectTag); // 加入全局副作用队列
}
// 核心职责5:Fiber收尾 - 合并子Fiber的副作用,向上传递
if (fiber.sibling) {
fiber.return.effects = mergeEffects(fiber.return.effects, fiber.effects);
}
}
// 判断是否为原生DOM类型组件
function isHostDOMType(type) {
return typeof type === 'string' && ['div', 'span', 'p', 'input'].includes(type);
}
// 判断是否需要中断(Scheduler 时间切片/高优先级抢占)
function shouldYield(expirationTime) {
return performance.now() >= expirationTime || hasHigherPriorityWork();
}
五、核心职责标注(分阶段 / 分方法)
1. beginWork(递阶段)核心职责
| 职责编号 | 具体职责 | 适用场景 | 核心目的 |
|---|---|---|---|
| 1 | 区分首屏 (mount)/ 更新 (update) | 所有 Fiber 节点 | 避免无意义的 DOM 操作 / Diff 计算 |
| 2 | 首屏渲染创建全新 Fiber 节点 | mount 阶段 | 构建初始 Fiber 树 |
| 3 | 更新阶段执行 Diff 算法 | update 阶段 | 计算节点增 / 删 / 改差异 |
| 4 | 生成子 Fiber 节点,构建子树 | 所有 Fiber 节点 | 为深度优先遍历提供后续节点 |
| 5 | 优先级判断与工作中断标记 | 所有 Fiber 节点 | 适配 Scheduler 可中断调度 |
2. completeWork(归阶段)核心职责
| 职责编号 | 具体职责 | 适用场景 | 核心目的 |
|---|---|---|---|
| 1 | 原生 DOM 组件创建真实 DOM | 宿主组件(div/span 等) | 映射 Fiber 到真实 DOM |
| 2 | 原生 DOM 组件更新属性 / Diff | 宿主组件 update 阶段 | 最小化 DOM 操作 |
| 3 | 子 DOM 节点挂载到父 DOM | 宿主组件 | 构建完整的真实 DOM 树 |
| 4 | 处理 Context/Props 透传 | 类组件 / Context 相关 | 保证组件层级数据一致性 |
| 5 | 收集当前 Fiber 的副作用 | 有更新的 Fiber 节点 | 为 Commit 阶段提供执行指令 |
| 6 | 合并子 Fiber 副作用并向上传递 | 非叶子节点 Fiber | 根 Fiber 统一管理所有副作用 |
六、关键执行流程(深度优先遍历示例)
以简单 DOM 结构 <div><p>React</p></div> 为例,展示 beginWork + completeWork 的执行顺序:

核心规律:先父后子执行 beginWork,先子后父执行 completeWork,叶子节点是第一个完成 beginWork + completeWork 的节点。
七、与 Fiber 架构 / 调度器的关联
- 可中断性:beginWork 执行过程中,若 Scheduler 判定需要中断(如 5ms 时间切片到期、高优先级任务抢占),会立即停止遍历,将当前未完成的 Fiber 标记为「工作中」,后续恢复时从该节点继续执行;
- 副作用隔离:调和阶段仅在 completeWork 中收集副作用,不执行任何真实操作(如 DOM 修改、生命周期调用),所有副作用统一在 Commit 阶段执行,保证更新的原子性;
- Fiber 映射:completeWork 为原生 DOM Fiber 建立 stateNode 映射(Fiber.stateNode = 真实 DOM),这是 React 后续操作 DOM 的核心依据,也是 Diff 算法能精准更新的基础。