🧑💻 引言
React Fiber 是 React 16 引入的全新协调引擎,它彻底重写了 React 的内部渲染机制,实现了 可中断渲染、优先级调度、时间切片 等核心能力。
本文将以 Fiber 的完整工作流程 为主线,结合源码拆解,分析 React Fiber 从 调度到 commit 的全过程,理解它如何保证 UI 高效、流畅渲染。
核心函数概览
React Fiber 的工作流程涉及以下 10 个核心函数:
- 调度层 :
performSyncWorkOnRoot
、performConcurrentWorkOnRoot
- 渲染层 :
renderRootSync
、renderRootConcurrent
- 循环层 :
workLoopSync
、workLoopConcurrent
- 单元层 :
performUnitOfWork
- 遍历层 :
beginWork
、completeUnitOfWork
、completeWork
一、调度层:渲染流程的入口
1.1 performSyncWorkOnRoot - 同步渲染入口
javascript
function performSyncWorkOnRoot(root) {
// 刷新副作用
flushPassiveEffects();
// 获取待处理的lanes
let lanes = getNextLanes(root, NoLanes);
// 执行同步渲染
let exitStatus = renderRootSync(root, lanes);
// 处理渲染结果...
}
核心职责:
- 作为同步渲染的统一入口点
- 处理副作用的刷新和清理
- 协调渲染状态和错误恢复
- 确保同步渲染的原子性
1.2 performConcurrentWorkOnRoot - 并发渲染入口
javascript
function performConcurrentWorkOnRoot(root, didTimeout) {
// 清除当前事件时间
currentEventTime = NoTimestamp;
currentEventTransitionLane = NoLanes;
// 执行并发渲染
let exitStatus = renderRootConcurrent(root, lanes);
// 处理时间切片和优先级调度...
}
核心特点:
- 支持时间切片的可中断渲染
- 实现优先级调度机制
- 处理并发模式下的复杂状态管理
二、渲染层:环境准备与初始化
2.1 renderRootSync - 同步渲染准备
javascript
function renderRootSync(root: FiberRoot, lanes: Lanes) {
// 设置执行上下文
const prevExecutionContext = executionContext;
executionContext |= RenderContext;
// 准备工作进度
if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
prepareFreshStack(root, lanes);
}
// 执行同步工作循环
do {
try {
workLoopSync();
break;
} catch (thrownValue) {
handleError(root, thrownValue);
}
} while (true);
// 恢复执行上下文
executionContext = prevExecutionContext;
}
2.2 renderRootConcurrent - 并发渲染准备
javascript
function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
// 类似的上下文设置
executionContext |= RenderContext;
// 准备工作进度
if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
prepareFreshStack(root, lanes);
}
// 执行并发工作循环
do {
try {
workLoopConcurrent();
break;
} catch (thrownValue) {
handleError(root, thrownValue);
}
} while (true);
}
两者主要区别:
- 同步模式不可中断,必须一次性完成
- 并发模式支持时间切片,可以被高优先级任务中断
三、循环层:工作循环的核心逻辑
3.1 workLoopSync - 同步工作循环
javascript
function workLoopSync() {
// 不可中断的循环处理
while (workInProgress !== null) {
performUnitOfWork(workInProgress);
}
}
3.2 workLoopConcurrent - 并发工作循环
javascript
function workLoopConcurrent() {
// 可中断的循环处理
while (workInProgress !== null && !shouldYield()) {
performUnitOfWork(workInProgress);
}
}
关键差异:
shouldYield()
函数检查是否需要让出执行权- 实现了 React 的时间切片机制
- 支持优先级更高的任务抢占执行
四、单元层:Fiber 节点的统一处理
4.1 performUnitOfWork - 工作单元处理核心
javascript
function performUnitOfWork(unitOfWork: Fiber): void {
const current = unitOfWork.alternate;
// 执行"递"阶段 - 向下遍历
let next = beginWork(current, unitOfWork, subtreeRenderLanes);
// 更新memoized属性
unitOfWork.memoizedProps = unitOfWork.pendingProps;
if (next === null) {
// 没有子节点,开始"归"阶段
completeUnitOfWork(unitOfWork);
} else {
// 继续处理子节点
workInProgress = next;
}
}
核心作用:
- 串联整个深度优先遍历过程
- 协调"递"和"归"两个阶段
- 维护 workInProgress 指针的正确流转
五、遍历层:深度优先遍历的具体实现
5.1 beginWork - "递"阶段处理
javascript
function beginWork(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes
): Fiber | null {
// 根据fiber.tag分发处理逻辑
switch (workInProgress.tag) {
case FunctionComponent:
return updateFunctionComponent(
current,
workInProgress,
Component,
resolvedProps,
renderLanes
);
case ClassComponent:
return updateClassComponent(
current,
workInProgress,
Component,
resolvedProps,
renderLanes
);
case HostComponent:
return updateHostComponent(current, workInProgress, renderLanes);
// ... 其他组件类型
}
}
主要职责:
- 根据 Fiber 节点类型执行相应的更新逻辑
- 处理 props 和 state 的变化
- 创建或复用子 Fiber 节点
- 通过 bailout 策略优化性能
5.2 completeUnitOfWork - "归"阶段协调
javascript
function completeUnitOfWork(unitOfWork: Fiber): void {
let completedWork = unitOfWork;
do {
const current = completedWork.alternate;
const returnFiber = completedWork.return;
// 调用completeWork处理当前节点
let next = completeWork(current, completedWork, subtreeRenderLanes);
if (next !== null) {
// 有新的工作产生,继续处理
workInProgress = next;
return;
}
// 处理兄弟节点
const siblingFiber = completedWork.sibling;
if (siblingFiber !== null) {
workInProgress = siblingFiber;
return;
}
// 回到父节点
completedWork = completedWork.return;
workInProgress = completedWork;
} while (completedWork !== null);
// 工作循环完成
workInProgressRootExitStatus = RootCompleted;
}
5.3 completeWork - "归"阶段具体处理
javascript
function completeWork(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes
): Fiber | null {
const newProps = workInProgress.pendingProps;
switch (workInProgress.tag) {
case HostComponent: {
// 处理DOM元素
if (current !== null && workInProgress.stateNode != null) {
// 更新现有元素
updateHostComponent(
current,
workInProgress,
type,
newProps,
rootContainerInstance
);
} else {
// 创建新元素
const instance = createInstance(
type,
newProps,
rootContainerInstance,
currentHostContext,
workInProgress
);
appendAllChildren(instance, workInProgress, false, false);
workInProgress.stateNode = instance;
}
break;
}
case HostText: {
// 处理文本节点
const newText = newProps;
if (current && workInProgress.stateNode != null) {
updateHostText(current, workInProgress, oldText, newText);
} else {
workInProgress.stateNode = createTextInstance(
newText,
rootContainerInstance,
currentHostContext,
workInProgress
);
}
break;
}
// ... 其他节点类型处理
}
// 冒泡属性到父节点
bubbleProperties(workInProgress);
return null;
}
主要功能:
- 根据 Fiber 类型处理 DOM 创建/更新
- 收集副作用标记
- 冒泡子节点的 lanes 和 flags
- 构建完整的副作用链
六、完整工作流程图
scss
用户触发更新 (setState, props变化等)
↓
调度器决定渲染模式
↓
performSyncWorkOnRoot ← → performConcurrentWorkOnRoot
↓ ↓
renderRootSync ← → renderRootConcurrent
↓ ↓
workLoopSync ← → workLoopConcurrent
↓ ↓
performUnitOfWork (循环处理每个Fiber节点)
↓
beginWork (递阶段)
↓
返回子节点 ← → 返回null
↓ ↓
继续处理子节点 completeUnitOfWork (归阶段)
↓ ↓
↓ completeWork
↓ ↓
↓ 处理兄弟节点或返回父节点
↓ ↓
←───────────────┘
↓
整个Fiber树遍历完成
↓
进入commit阶段处理副作用
↓
DOM更新完成
七、核心设计原理
7.1 双缓存架构
React Fiber 使用双缓存架构,维护两棵 Fiber 树:
- current 树:当前页面显示的 UI 对应的 Fiber 树
- workInProgress 树:正在内存中构建的 Fiber 树
两棵树通过alternate
属性相互引用,完成渲染后进行角色互换。
7.2 深度优先遍历
Fiber 树的遍历采用深度优先策略,分为两个阶段:
- 递阶段 :从根节点向叶子节点遍历,调用
beginWork
- 归阶段 :从叶子节点向根节点回溯,调用
completeWork
7.3 可中断渲染
并发模式下,React 通过以下机制实现可中断渲染:
- 时间切片 :通过
shouldYield()
检查剩余时间 - 优先级调度:使用 lanes 模型管理任务优先级
- 工作暂停与恢复:保存工作进度,支持任务的暂停和恢复
7.4 副作用收集
在遍历过程中,React 收集所有需要执行的副作用:
- Placement:插入新节点
- Update:更新现有节点
- Deletion:删除节点
- Passive:异步副作用(useEffect 等)
八、性能优化策略
8.1 Bailout 优化
当组件的 props 和 state 没有变化时,React 会跳过该组件及其子树的处理:
javascript
// 在beginWork中的bailout检查
if (
current !== null &&
oldProps === newProps &&
!hasLegacyContextChanged() &&
!includesSomeLane(renderLanes, updateLanes)
) {
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
8.2 lanes 优先级模型
React 使用 lanes 模型管理任务优先级:
- SyncLane:同步任务,最高优先级
- DefaultLane:默认优先级
- TransitionLane:过渡动画优先级
- RetryLane:重试任务优先级
8.3 时间切片机制
javascript
function shouldYield() {
return getCurrentTime() >= deadline;
}
通过检查当前时间是否超过时间片截止时间,决定是否让出执行权。