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

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

scss 复制代码
setState(newValue);
// → assign lane: DefaultLane or SyncLane

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

2. 根节点调度表(PendingLanes)

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

ini 复制代码
root.pendingLanes = SyncLane | TransitionLane;

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

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

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

Lane Scheduler 优先级
SyncLane ImmediatePriority
InputContinuousLane UserBlockingPriority
DefaultLane NormalPriority
TransitionLane LowPriority
IdleLane IdlePriority

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

如何中断低优先级任务?

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

scss 复制代码
shouldYield()

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

less 复制代码
if (shouldYield()) {
  // 暂停当前任务,下次继续
}

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


🧪 六、startTransition 的本质

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

场景示例:

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

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


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

React 会在根节点计算:

scss 复制代码
getNextLanes(root)

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

kotlin 复制代码
if (SyncLane in pending) return SyncLane;
else if (InputContinuousLane in pending) return InputContinuousLane;
else if (DefaultLane in pending) return DefaultLane;
...

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


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

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

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

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

相关推荐
又又呢26 分钟前
前端面试题总结——webpack篇
前端·webpack·node.js
dog shit1 小时前
web第十次课后作业--Mybatis的增删改查
android·前端·mybatis
我有一只臭臭1 小时前
el-tabs 切换时数据不更新的问题
前端·vue.js
七灵微1 小时前
【前端】工具链一本通
前端
Nueuis2 小时前
微信小程序前端面经
前端·微信小程序·小程序
_r0bin_5 小时前
前端面试准备-7
开发语言·前端·javascript·fetch·跨域·class
IT瘾君5 小时前
JavaWeb:前端工程化-Vue
前端·javascript·vue.js
potender5 小时前
前端框架Vue
前端·vue.js·前端框架
站在风口的猪11085 小时前
《前端面试题:CSS预处理器(Sass、Less等)》
前端·css·html·less·css3·sass·html5
程序员的世界你不懂6 小时前
(9)-Fiddler抓包-Fiddler如何设置捕获Https会话
前端·https·fiddler