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 → 中断继续下次

相关推荐
望获linux30 分钟前
【Linux基础知识系列】第一百一十篇 - 使用Nmap进行网络安全扫描
java·linux·开发语言·前端·数据库·信息可视化·php
乘乘凉35 分钟前
Python中函数的闭包和装饰器
前端·数据库·python
Fantastic_sj1 小时前
部分CSS笔试题讲解
前端·css
雷达学弱狗3 小时前
链式法则解释上游梯度应用
开发语言·前端·javascript
爱隐身的官人5 小时前
爬虫基础学习-爬取网页项目(二)
前端·爬虫·python·学习
Jackson@ML6 小时前
使用字节旗下的TREA IDE快速开发Web应用程序
前端·ide·trea
烛阴8 小时前
解锁 TypeScript 的元编程魔法:从 `extends` 到 `infer` 的条件类型之旅
前端·javascript·typescript
前端开发爱好者9 小时前
弃用 ESLint + Prettier!快 35 倍的 AI 格式化神器!
前端·javascript·vue.js
vivi_and_qiao9 小时前
HTML的form表单
java·前端·html
骑驴看星星a9 小时前
Vue中的scoped属性
前端·javascript·vue.js