Fiber 是 React 16 引入的全新架构,旨在解决大型应用更新时的性能问题,特别是支持增量渲染和更好的调度控制。
Fiber 是对虚拟 DOM 的扩展,每个组件对应一个 Fiber 节点:
function FiberNode(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
// 实例相关
this.tag = tag; // 组件类型 (函数组件/类组件/DOM节点等)
this.key = key; // 唯一标识
this.elementType = null; // React元素类型
this.type = null; // 组件函数/类或DOM标签名
this.stateNode = null; // 对应的真实DOM节点或组件实例
// Fiber树结构相关
this.return = null; // 父Fiber
this.child = null; // 第一个子Fiber
this.sibling = null; // 下一个兄弟Fiber
this.index = 0; // 在兄弟中的索引
// 副作用相关
this.flags = NoFlags; // 标记需要进行的操作(插入/更新/删除等)
this.subtreeFlags = NoFlags; // 子树中的副作用
this.deletions = null; // 需要删除的子节点
// 状态与props
this.pendingProps = pendingProps; // 新的props
this.memoizedProps = null; // 上次渲染使用的props
this.updateQueue = null; // 状态更新队列
this.memoizedState = null; // 上次渲染使用的state
this.dependencies = null; // contexts, events等依赖
// 调度相关
this.alternate = null; // 用于连接current和workInProgress树
this.lanes = NoLanes; // 调度优先级
this.childLanes = NoLanes; // 子树的调度优先级
}
React 使用双缓存技术维护两棵 Fiber 树:
function performUnitOfWork(fiber) {
// 开始工作: 创建新的Fiber或复用现有Fiber
beginWork(fiber);
if (fiber.child) {
return fiber.child; // 深度优先遍历
}
// 没有子节点则处理兄弟节点
let nextFiber = fiber;
while (nextFiber) {
completeWork(nextFiber); // 完成当前节点工作
if (nextFiber.sibling) {
return nextFiber.sibling; // 返回兄弟节点
}
nextFiber = nextFiber.return; // 回溯到父节点
}
}
function commitRoot(root) {
// 第一阶段: 调用getSnapshotBeforeUpdate等生命周期
commitBeforeMutationEffects();
// 第二阶段: 执行DOM操作
commitMutationEffects();
// 切换current指针
root.current = finishedWork;
// 第三阶段: 调用componentDidMount/Update等生命周期
commitLayoutEffects();
}
React 的协调算法基于两个假设优化性能:
比较根元素:
比较子元素:
function reconcileChildrenArray(
returnFiber: Fiber,
currentFirstChild: Fiber | null,
newChildren: Array<*>,
lanes: Lanes,
): Fiber | null {
let resultingFirstChild: Fiber | null = null;
let previousNewFiber: Fiber | null = null;
let oldFiber = currentFirstChild;
let lastPlacedIndex = 0;
let newIdx = 0;
let nextOldFiber = null;
// 第一轮遍历: 处理可复用的节点
for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) {
if (oldFiber.index > newIdx) {
nextOldFiber = oldFiber;
oldFiber = null;
} else {
nextOldFiber = oldFiber.sibling;
}
const newFiber = updateSlot(
returnFiber,
oldFiber,
newChildren[newIdx],
lanes,
);
if (newFiber === null) {
if (oldFiber === null) {
oldFiber = nextOldFiber;
}
break; // key不匹配,跳出循环
}
// 标记是否需要移动
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
// 构建新Fiber链表
if (previousNewFiber === null) {
resultingFirstChild = newFiber;
} else {
previousNewFiber.sibling = newFiber;
}
previousNewFiber = newFiber;
oldFiber = nextOldFiber;
}
// 第二轮遍历: 处理剩余节点
// ...省略后续处理代码...
return resultingFirstChild;
}
React 使用 lanes 模型管理更新优先级:
function scheduleUpdateOnFiber(
fiber: Fiber,
lane: Lane,
eventTime: number,
) {
// 标记更新优先级
const root = markUpdateLaneFromFiberToRoot(fiber, lane);
if (root === null) return;
// 根据优先级调度更新
if (lane === SyncLane) {
// 同步更新
performSyncWorkOnRoot(root);
} else {
// 异步更新
ensureRootIsScheduled(root, eventTime);
}
}
React 使用 requestIdleCallback
或 MessageChannel
模拟实现时间切片:
function workLoopConcurrent() {
// 在浏览器空闲时执行工作
while (workInProgress !== null && !shouldYield()) {
performUnitOfWork(workInProgress);
}
// 如果还有未完成的工作,稍后继续
if (workInProgress !== null) {
scheduleCallback(performConcurrentWorkOnRoot.bind(null, root));
}
}
Fiber 架构通过以下机制实现了高效的协调更新:
这种架构使 React 能够处理大型复杂应用的渲染需求,同时保持流畅的用户体验。