React Fiber的优先级系统你知道多少?

191 阅读3分钟

React Fiber 的优先级系统是它支持异步渲染、任务调度和并发特性的核心机制之一。这个系统允许 React 区分不同类型的更新任务,按优先级顺序执行,从而实现:

  • ✅ 用户交互响应优先
  • ✅ 渲染任务可以被打断
  • ✅ 更流畅的动画和输入体验

🧠 一、为什么需要优先级系统?

传统的 React 15 或 Vue 2 中,所有更新都是同步更新:一旦开始就必须执行完,哪怕中间来了更紧急的任务(比如用户点击、输入),也得等当前渲染结束才能响应。

这就可能导致:

  • 页面卡顿
  • 输入延迟
  • 动画掉帧

为了解决这个问题,React Fiber 将更新拆成小任务,并引入“优先级”系统来决定哪些任务先执行、哪些可以延后或打断重来


🛣️ 二、Fiber 优先级系统的发展历程

React 16 之前:使用 expiration time(过期时间)

  • 用时间戳表示优先级
  • 越小越紧急
  • 存在调度不够灵活的问题

React 17 之后:引入 Lane 模型(车道系统)

  • 每一个更新被分配一个 Lane
  • Lane 是二进制标识位(bitmask)
  • 可组合(多种更新类型可以合并执行)
  • 支持并发任务管理

🧩 三、Lane 模型详解

Lane 是一个 31 位的二进制位,每一位代表一种优先级。

常见 Lane 类型

Lane 名称示例说明优先级
SyncLane同步事件onClicksetState🟥 最高
InputContinuousLane滚动、拖拽滑动条、拖拽🟧 很高
DefaultLane普通更新状态更新、数据变化🟨 中等
TransitionLane过渡更新startTransition🟦 可打断
IdleLane闲时执行日志、后台任务🟩 最低

一个更新可以包含多个 Lane,比如同时是 Transition 和 Default,可以合并调度。


🔀 四、优先级调度的执行过程

1. 触发更新时选择 Lane

setState(newValue);
// → assign lane: DefaultLane or SyncLane

由调度器根据上下文(事件、transition)为更新分配合适的 Lane。

2. 根节点调度表(PendingLanes)

每棵 Fiber 树的 root 上维护一个 pendingLanes 记录哪些 Lane 上有未处理的更新。

root.pendingLanes = SyncLane | TransitionLane;

3. 调度器根据优先级挑选任务

React 使用自己的调度器包 scheduler,模拟浏览器空闲时间。

调度器根据 Lane → 对应的 Scheduler 优先级:

LaneScheduler 优先级
SyncLaneImmediatePriority
InputContinuousLaneUserBlockingPriority
DefaultLaneNormalPriority
TransitionLaneLowPriority
IdleLaneIdlePriority

🔂 五、优先级系统与中断机制的协同

如何中断低优先级任务?

workLoopConcurrent 中,每处理一个单元后会调用:

shouldYield()

用于判断是否该中断当前任务,让高优先级任务插队。

if (shouldYield()) {
  // 暂停当前任务,下次继续
}

这种机制是 Fiber 调度的核心:时间分片 + 优先级抢占


🧪 六、startTransition 的本质

startTransition(() => {
  setState(slowData);
});
  • startTransition 会将内部更新标记为 TransitionLane
  • React 可以在空闲时执行,不会打断用户输入
  • 用户输入如点击、打字触发的 SyncLane 会插队并立即执行

场景示例:

<input onChange={(e) => {
  setInput(e.target.value);           // SyncLane
  startTransition(() => {
    setFilteredList(slowFilter());   // TransitionLane
  });
}} />

用户输入不会卡顿,筛选操作可以延后一点点再更新。


🔍 七、React 是怎么判断哪个 Lane 要先执行?

React 会在根节点计算:

getNextLanes(root)

按优先级从高到低取出下一个要处理的 Lane:

if (SyncLane in pending) return SyncLane;
else if (InputContinuousLane in pending) return InputContinuousLane;
else if (DefaultLane in pending) return DefaultLane;
...

然后只构建对应 Lane 的 Fiber 子树,提高性能。


🧠 八、总结:优先级系统的核心价值

能力描述
任务抢占低优先级任务可以被高优先级插队中断
时间分片渲染被拆成小单元,每一帧可以只做一部分工作
多任务组合多个任务可以用 Lane 合并执行
更好用户体验实现不卡顿的输入、过渡和动画

📌 最后一张图理解优先级系统

  setState → 分配 Lane(Sync / Default / Transition)
           ↓
   Root Fiber.pendingLanes 标记该 Lane
           ↓
   调度器选择最高优先级 Lane
           ↓
   构建该 Lane 的 Fiber 子树
           ↓
   每帧执行部分任务 → shouldYield → 中断继续下次