在 React 15 及更早版本中,React 使用的是递归渲染(Stack Reconciler):
这违背了现代 Web 应用对 “响应性” 和 “可中断性” 的需求。
从 React 16 开始,Facebook 团队引入了全新的 Fiber 架构:
React 的 Fiber 架构主要实现在 react-reconciler
包中,以下是关键源码文件:
文件路径 | 功能描述 |
---|---|
packages/react-reconciler/src/ReactFiber.js |
定义 Fiber 节点结构与创建逻辑 |
packages/react-reconciler/src/ReactFiberRoot.js |
管理 Fiber 树根节点(root) |
packages/react-reconciler/src/ReactFiberWorkLoop.js |
工作循环主流程,负责任务调度与执行 |
packages/react-reconciler/src/ReactFiberLane.js |
Lane 模型,用于表示更新的优先级 |
packages/scheduler/src/Scheduler.js |
任务调度器核心,基于 requestIdleCallback 或 setTimeout |
// packages/react-reconciler/src/ReactFiber.js
function FiberNode(
tag, // 节点类型(FunctionComponent / ClassComponent / HostComponent 等)
pendingProps, // 待处理的 props
key, // 唯一标识符
mode // 模式(如 ConcurrentMode)
) {
this.tag = tag;
this.key = key;
this.type = null; // 组件类型或 DOM 标签名
this.stateNode = null; // 对应的真实 DOM 或组件实例
// 父子兄弟指针
this.return = null; // 父节点
this.child = null; // 第一个子节点
this.sibling = null; // 下一个兄弟节点
// 当前状态
this.memoizedState = null; // 上一次渲染时的状态(如 state、context)
this.updateQueue = null; // 更新队列
this.memoizedProps = null; // 上一次渲染时的 props
// 优先级相关
this.lanes = NoLanes; // 表示当前 Fiber 的优先级
this.childLanes = NoLanes; // 子节点的优先级集合
// 双缓冲机制(current <-> workInProgress)
this.alternate = null;
}
属性名 | 含义 |
---|---|
tag |
表示该节点的类型(HostComponent、FunctionComponent 等) |
type |
组件类型或 DOM 标签名称 |
stateNode |
对应的真实 DOM 或类组件实例 |
return , child , sibling |
构建 Fiber 树的链表结构 |
pendingProps |
新传入的 props |
memoizedProps |
上次渲染使用的 props |
memoizedState |
上次渲染使用的 state |
lanes |
当前节点的优先级 |
alternate |
指向另一个 Fiber(用于双缓冲机制) |
为了实现 “时间切片(Time Slicing)” 和 “可中断渲染”,React 使用了以下机制:
工作循环的核心逻辑在 ReactFiberWorkLoop.js
中,主要函数如下:
function workLoopConcurrent() {
while (workInProgress !== null && !shouldYield()) {
performUnitOfWork(workInProgress);
}
}
workInProgress
:当前正在处理的 Fiber 节点;performUnitOfWork
:处理单个 Fiber 节点;shouldYield()
:判断是否应该让出主线程给更高优先级任务;function shouldYield() {
return !didTimeout && getCurrentTime() >= deadline;
}
deadline
:当前帧的时间限制;didTimeout
:是否超时强制执行;React 使用 Lane 模型 来表示更新的优先级。每个 Lane 是一个位掩码(bitmask),支持组合使用。
SyncLane
:同步更新(如点击事件);InputDiscreteLane
:离散输入(如按键);DefaultLane
:普通更新;IdleLane
:低优先级更新(如非关键 UI);export const SyncLane: Lanes = 0b0000000000000000000000000000001;
export const InputDiscreteLane: Lanes = 0b0000000000000000000000000000100;
export const DefaultLane: Lanes = 0b0000000000000000000000000100000;
export const IdleLane: Lanes = 0b1000000000000000000000000000000;
export function getHighestPriorityLane(lanes: Lanes): Lane {
return lanes & -lanes;
}
以下是对这段 React Lane 模型代码的逐行详细解释,包括位掩码(bitmask)表示优先级、Lane 的定义以及如何获取最高优先级 Lane 的函数逻辑。
export const SyncLane: Lanes = 0b0000000000000000000000000000001;
0b
表示法,只有最低位为 1
,代表最高优先级(React 中同步更新优先级最高)。1
。export const InputDiscreteLane: Lanes = 0b0000000000000000000000000000100;
1
,优先级低于 Sync,高于普通更新。4
。export const DefaultLane: Lanes = 0b0000000000000000000000000100000;
1
。32
。export const IdleLane: Lanes = 0b1000000000000000000000000000000;
1
(注意:JS 中 Number 是双精度浮点数,这里用的是 32 位掩码模拟)。2147483648
。在 React 中:
Lanes
是一个 位掩码集合,可以同时包含多个 Lane;|
,例如:const updateLanes = SyncLane | DefaultLane;
&
,例如:if (updateLanes & InputDiscreteLane) {
// 存在这个优先级
}
export function getHighestPriorityLane(lanes: Lanes): Lane {
return lanes & -lanes;
}
该函数用于从一组 Lane 中提取出 优先级最高的那个 Lane。
lanes & -lanes
是一个经典的 “取最低位的 1” 的位运算技巧。1
就是最高优先级的 Lane。const lanes = SyncLane | DefaultLane; // 二进制:0000000000000000000000000100001
getHighestPriorityLane(lanes); // 返回 SyncLane(0b0000000000000000000000000000001)
lanes = 0b0000000000000000000000000100001
(十进制:33)-lanes = 0b1111111111111111111111111011111
(补码形式)lanes & -lanes = 0b0000000000000000000000000000001
(即 SyncLane)特性 | 描述 |
---|---|
位掩码机制 | 支持组合多个优先级,节省内存和提高性能 |
优先级判断高效 | 通过位运算快速判断优先级高低 |
支持并发更新 | 可以区分紧急更新和低优先级更新,实现中断恢复 |
细粒度控制 | 每个 Lane 表示一类更新类型,便于调度器做决策 |
如果你想进一步理解 Lane 模型在 React 源码中的实际应用,可以继续学习以下内容:
// 创建一个 Fiber 节点的函数(工厂函数)
function createFiber(tag, pendingProps, key) {
// 返回一个表示 Fiber 的对象,包含核心属性
return {
// 节点类型:如 FunctionComponent、ClassComponent、HostComponent(div/span)等
tag,
// 唯一标识符,用于 Diffing 算法中判断是否是同一个节点
key,
// 新传入的 props,尚未处理
pendingProps,
// 组件类型或 DOM 标签名(如 'div'、MyComponent)
type: null,
// 对应的真实 DOM 或类组件实例
stateNode: null,
// 指向父 Fiber 节点
return: null,
// 第一个子 Fiber 节点
child: null,
// 下一个兄弟 Fiber 节点
sibling: null,
// 上一次渲染时使用的 state(如组件状态、context 等)
memoizedState: null,
// 存储更新队列(如 useState、useReducer 的更新)
updateQueue: null,
// 上一次渲染时使用的 props
memoizedProps: null,
// 表示当前 Fiber 的优先级(Lane 模型中的位掩码)
lanes: 0,
// 双缓冲机制:指向另一个 Fiber 实例(current <-> workInProgress)
alternate: null,
};
}
// 当前正在处理的 Fiber 节点
let workInProgress = null;
/**
* 调度一个 Fiber 更新任务
* @param {Object} fiber - 需要更新的 Fiber 节点
* @param {number} lane - 该更新的优先级(Lane 模型)
*/
function scheduleUpdateOnFiber(fiber, lane) {
// 打印日志:记录即将调度哪个 Fiber 和它的优先级
console.log(`Scheduled update on ${fiber.key} with lane ${lane}`);
// 设置当前工作节点为传入的 fiber
workInProgress = fiber;
// 使用 requestIdleCallback 来异步执行任务(模拟)
requestIdleCallback(performUnitOfWork);
}
/**
* 执行一个 Fiber 工作单元(即处理一个 Fiber 节点)
* @param {Object} unitOfWork - 正在处理的 Fiber 节点
*/
function performUnitOfWork(unitOfWork) {
// 获取当前要处理的 Fiber 节点
const fiber = unitOfWork;
// 打印日志:表示开始处理这个 Fiber
console.log(`Processing fiber: ${fiber.key}`);
// 如果有子节点,则递归处理子节点
if (fiber.child) {
performUnitOfWork(fiber.child); // 处理子节点
}
// 如果有兄弟节点,则递归处理兄弟节点
if (fiber.sibling) {
performUnitOfWork(fiber.sibling); // 处理兄弟节点
}
// 当前 Fiber 完成处理后调用完成函数
completeUnitOfWork(fiber);
}
/**
* 当某个 Fiber 节点处理完成后执行的逻辑
* @param {Object} fiber - 已处理完成的 Fiber 节点
*/
function completeUnitOfWork(fiber) {
// 打印日志:表示该 Fiber 已完成处理
console.log(`Completed processing fiber: ${fiber.key}`);
}
/**
* 模拟浏览器的 requestIdleCallback API
* 在实际 React 中使用的是 scheduler 包来实现更精确的任务调度
* @param {Function} cb - 要执行的回调函数
*/
function requestIdleCallback(cb) {
/**
* 使用 setTimeout 模拟浏览器空闲时间
* 0ms 后执行回调,并传入一个带有 timeRemaining 方法的对象
* timeRemaining 模拟剩余可用时间(单位:毫秒)
*/
setTimeout(() => cb({ timeRemaining: () => 5 }), 0); // 模拟每次最多执行 5ms
}
这段代码是对 React Fiber 架构与任务调度机制的一个简化模拟版本,虽然没有涉及真实 React 的双缓冲、副作用收集、优先级 Lane 模型等复杂机制,但已经涵盖了以下核心思想:
requestIdleCallback
模拟异步调度;child/sibling/return
实现 Fiber 树的遍历;React 的 Fiber 架构与任务调度中涉及多个经典设计模式:
设计模式 | 应用场景 |
---|---|
链表结构(Linked List) | Fiber 树通过 return、child、sibling 构建 |
双缓冲(Double Buffering) | current 与 workInProgress Fiber 的交替使用 |
策略模式(Strategy) | 不同优先级(Lane)采用不同调度策略 |
观察者模式(Observer) | 状态变化触发重新渲染 |
命令模式(Command) | 收集副作用(Placement / Update / Deletion)统一提交 |
责任链模式(Chain of Responsibility) | 从 root 到子节点依次处理更新任务 |
本教程深入剖析了 React 的 Fiber 架构与任务调度机制,包括: