当前位置: 首页 > news >正文

React Filber及核心原理

1. React Fiber 的核心目标‌

  • 增量渲染‌:将大型更新拆解为可中断的小任务(时间切片),避免阻塞

  • 主线程‌优先级调度‌:动态管理任务执行顺序(如用户交互 > 动画 > 数据加载)。

  • 与浏览器协作‌:利用浏览器渲染周期(rAF)和空闲时间(rIC理念)优化性能。

一句话定义:

React Fiber是React 16+的核心重写算法,通过增量渲染和任务分片实现高性能异步更新。旨在解决传统同步渲染阻塞主线程导致的卡顿问题。

2. React Fiber 的核心原理

之前的版本中,React使用递归的方式处理组件树的更新,这个过程是同步的,一旦开始就不能中断,可能导致长时间占用主线程,造成界面卡顿,尤其是在处理复杂组件时。

Fiber是将组件树拆解为‌链表结构‌Fiber 节点(每个节点对应一个可中断/恢复的“工作单元”),通过‌优先级调度‌(如用户交互任务优先)和‌时间切片‌(利用浏览器空闲时间分批次处理任务),实现异步可中断的渲染流程。

Fiber 在协调阶段(Render Phase)增量构建虚拟树并标记副作用(如 DOM 更新),在提交阶段(Commit Phase)同步执行所有变更,同时通过‌双缓冲机制‌(交替使用 current 和 workInProgress 树)和‌副作用链表‌优化性能,从而支持并发模式(Concurrent Mode),显著提升复杂应用的响应速度与流畅度。

在 React 的 Fiber 架构中,requestAnimationFrame、‌链表‌ 和 ‌调度器‌三者紧密结合,主要体现在 ‌任务调度策略‌ 和 ‌执行效率优化‌

2.1. Filber中的链表(任务存储与遍历‌)

Fiber 树本身的链表结构‌和‌副作用链表(effect list)‌是‌两个不同的链表

2.1.1. Fiber 树链表(主链表)‌

作用‌:

表示组件树完整结构,用于协调阶段(reconciliation)遍历任务分片

数据结构‌:

每个 Fiber 节点通过 child、sibling、return 三个指针构成‌树形链表‌(深度优先遍历的线性化结构)。

class FiberNode {child: Fiber | null;    // 第一个子节点sibling: Fiber | null;  // 下一个兄弟节点return: Fiber | null;   // 父节点// ... 其他属性(type, stateNode 等)
}

特点‌:

用于递归的‌可中断恢复‌(通过保存当前处理的 Fiber 节点指针)。
是 React 处理组件更新的‌核心数据结构‌。

‌与调度器的关系‌
每个链表节点(FiberNode)包含任务信息优先级标记指针(child/sibling/return)
调度器通过链表实现‌可中断恢复‌:保存当前节点指针,下次从中断处继续

2.1.2. 副作用链表(effect list)‌

作用‌:

收集所有需要执行副作用的 Fiber 节点(如 DOM 操作、生命周期调用),在提交阶段(commit phase)批量处理。

‌数据结构‌:

通过 firstEffect、lastEffect、nextEffect 指针构成的‌单向链表‌。

class FiberNode {firstEffect: Fiber | null; // 链表头lastEffect: Fiber | null;  // 链表尾nextEffect: Fiber | null;  // 下一个副作用节点effectTag: Placement | Update | Deletion; // 副作用类型
}

‌特点‌:

Fiber 树的‌子集‌,仅包含需要处理的节点。
协调阶段动态构建,提交阶段直接遍历此链表执行 DOM 操作

副作用链表(effect list)的工作流程‌

每个Fiber节点在完成工作后,如果有副作用,会被添加到链表中。firstEffect和lastEffect用来指向链表的头和尾,nextEffect是每个节点的指针。在提交阶段,React遍历这个链表,依次处理每个副作用,如DOM更新生命周期方法的调用等。这种结构使得React能够高效地批量处理副作用,而不必在协调阶段频繁操作DOM,从而提高性能。

React Fiber 架构中任务调度与副作用处理的优先级机制:
于优先级,副作用链表可能并不直接管理优先级,而是由调度器决定哪些Fiber节点需要先处理。高优先级的更新会导致重新构建副作用链表,确保紧急的副作用先执行。例如,用户输入触发的更新可能打断正在进行的渲染,优先处理相关副作用,然后再处理低优先级的任务。

  • ‌中断与恢复‌:高优先级任务可中断当前协调过程,保留未完成的副作用链表,后续恢复时继续构建。
  • 多优先级链表‌:React 内部维护多个链表(如 pendingPassiveEffects),区分同步与异步(如 useEffect)副作用。
    •   ‌同步副作用‌:useLayoutEffect 在提交阶段同步执行。
      
    •   ‌异步副作用‌:useEffect 被推入异步队列,在浏览器空闲时处理。
      

在构建链表时,React可能采用深度优先的后序遍历方式确保子节点的副作用在父节点之前处理,这样在DOM操作时可以正确应用变更。例如,当子节点需要被删除时,先处理子节点的删除,再处理父节点的更新,避免父节点更新后子节点不存在导致的错误。

最后,需要理解副作用链表在React整个渲染流程中的位置。协调阶段(render phase)负责找出所有需要变更的节点构建副作用链表,提交阶段(commit phase)遍历链表执行变更。这种分离使得React可以异步处理渲染,提高响应能力。

2.1.3. 为什么分开设计?‌

1‌.关注点分离‌

Fiber 树负责‌任务调度和中断恢复‌(协调阶段)。
副作用链表负责‌高效执行 DOM 操作‌(提交阶段)。

‌2.性能优化‌:

提交阶段只需遍历少量副作用节点,避免全树遍历。
批量处理 DOM 更新,减少浏览器重排/重绘。

总结‌:
‌不是同一个链表‌,但副作用链表是 Fiber 树的衍生结构
Fiber 树是‌全局任务管理‌的骨架,副作用链表是‌局部优化‌的结果。
两者协作实现 React 的‌可中断渲染‌和‌高效更新‌

在这里插入图片描述

2.2‌. requestAnimationFrame(rAF)‌:调度时机控制‌

‌requestAnimationFrame(rAF)‌ 是浏览器提供的原生 API,用于在下一次屏幕刷新(通常是每秒 60 次,即 16.6ms/帧)前执行回调函数。

‌作用‌

在每一帧渲染前执行高优先级任务(如动画、UI 更新)

‌与调度器的关系‌:

React 调度器用 rAF 作为‌高优先级任务触发时机‌,确保视觉更新及时
避免 setTimeout 因时间不精确导致的丢帧问题

核心目标:

  • 动画与视觉更新‌:

rAF 确保回调函数在浏览器‌下一帧渲染前执行‌,与屏幕刷新率(60Hz)同步,避免丢帧。

  • React 中的应用‌:

高优先级任务对齐‌:React 将动画、布局更新等高优先级任务标记为与 rAF 同步执行。

‌避免布局抖动‌:在 rAF 回调中批量处理 DOM 读写,减少强制布局计算(如 offsetWidth)。

特性requestAnimationFramerequestIdleCallback
触发时机每帧开始前(16.7ms/60FPS)浏览器空闲时(无高优先级任务)
用途动画、视觉更新后台任务(日志、预加载)
优先级高(与渲染强相关)低(可被高优先级任务打断)
React调度参考影响高优先级任务分片启发低优先级任务分片(如并发渲染)
执行耗时限制需控制在3-4ms以内默认50ms(通过timeout参数可调)
兼容性IE10+需polyfill(如React的scheduler

2.3. React 自研调度器(Scheduler)

是其并发模式(Concurrent Mode)的核心底层机制,相比传统更新调度方式具有以下显著优势:

2.3.1.优先级调度‌

‌ 更精细的任务优先级控制‌

  • 5级优先级划分‌:
    Immediate(同步) > UserBlocking(用户交互) > Normal(默认) > Low(数据加载) > Idle(空闲任务)

协作流程示例‌

  • ‌用户点击按钮‌(Immediate 优先级):
    同步执行回调,更新状态,标记相关 Fiber 节点。
  • ‌触发动画‌or搜索建议(UserBlocking 优先级):
    将更新任务放入 rAF 队列,确保下一帧渲染前完成。
  • ‌数据加载‌(Low 优先级):
    拆分任务为 5ms 的块,在调度器检测到空闲时逐步执行。
  • 动态调整‌:高优先级任务可中断低优先级任务(如渲染中途响应用户点击)。
2.3.2.避免浏览器主线程阻塞
1.时间切片(Time Slicing)的概念

时间切片逻辑‌:将任务拆分5ms 的块,动态检查剩余时间,通过shouldYield()判断是否让出主线程,保证UI响应。优先处理用户输入高优先级事件。

用于将渲染任务分解成更小的单元,这样可以在浏览器的空闲时段执行这些任务,避免阻塞用户交互。这听起来类似于浏览器的requestIdleCallback API,允许在空闲时间执行任务,但React可能自己实现了更精细的控制。

requestIdleCallback(rIC)的理念‌

空闲时段处理低优先级任务‌:rIC 在浏览器空闲时执行非紧急任务(如日志、预加载),避免干扰关键渲染和交互。

2.‌基于MessageChannel的调度‌:

React 自研调度器,通过 MessageChannelsetTimeout ‌模拟空闲检测‌
MessageChannel相比setTimeout,利用事件循环的宏任务机制更精准控制执行时机,避免任务堆积导致卡顿。

React Fiber 未直接使用 rIC‌:这是因为rIC的浏览器兼容性触发频率不够理想。React的调度器会将任务分成小的时间片,并在每个时间片结束时检查是否有更高优先级的任务需要处理,从而避免长时间阻塞主线程。

2.3.3. 更智能的后台任务处理‌

空闲期利用‌:
通过requestIdleCallback的polyfill(兼容方案),在浏览器空闲时执行低优先级任务(如日志上报、预渲染)。

‌任务饥饿保护‌:
防止低优先级任务因长期无法执行被“饿死”(超过超时时间会强制提升优先级)。

2.3.4. 与React深度集成‌

‌ 协调器(Reconciler)联动‌:

调度器知晓Fiber节点结构,可精准暂停/恢复渲染任务,实现可中断渲染。

‌并发特性基础‌:

支持startTransition、useDeferredValue等API的底层依赖。

对比传统调度方案‌

能力传统setState更新React调度器
任务中断✗ 不可中断✔ 高优任务可中断低优任务
浏览器阻塞可能阻塞主线程通过时间切片避免阻塞
优先级控制无差别处理5级动态优先级
后台任务利用依赖手动实现内置空闲期调度

2.4 双缓冲机制

2.4.1. 双缓冲的定义

Fiber 架构的核心机制‌,用于在 ‌协调阶段(Reconciliation)‌ 和 ‌提交阶段(Commit)‌ 之间高效管理组件状态更新,确保 React 的 ‌可中断渲染‌ 和 ‌一致性更新‌

双缓冲是计算机图形学中的经典技术,指 ‌同时维护两套数据结构‌:

  • 当前缓冲(Current)‌:正在渲染或已渲染的 UI 状态(对应屏幕上显示的内容)。
  • 工作缓冲(WorkInProgress,WIP)‌:正在计算的新状态(尚未提交到屏幕)。

React 借用这一概念,在 Fiber 架构中维护 ‌两棵 Fiber 树‌:

  • current 树‌:当前已渲染的 Fiber 树(对应真实 DOM)。
  • workInProgress 树‌:正在构建的新 Fiber 树(用于计算更新)。
2.4.2. 双缓冲的核心流程‌

‌(1) 协调阶段(Reconciliation)‌

  • React 从 current 树克隆出 workInProgress 树(通过 alternate 指针关联)。
  • workInProgress 树上进行 ‌Diff 计算‌标记需要更新的节点(effectTag)。
  • 如果任务被中断(如高优先级任务插入),可以丢弃 workInProgress 树并重新开始,而不会影响 current 树(已渲染的 UI)。

‌(2) 提交阶段(Commit)‌
当 workInProgress 树构建完成,React 执行 ‌原子性切换‌:

root.current = finishedWork; // 切换 current 和 workInProgress

此时:

  • 新的 workInProgress 树变为 current 树(对应最新 UI)。
  • 旧的 current 树变为新的 workInProgress 树(供下次更新使用)。

通过维护两棵 Fiber 树(currentworkInProgress),实现:

  • 计算与渲染分离。
  • 高优先级任务抢占。
  • 无闪烁的 UI 更新。

最终提升复杂应用的流畅度和响应速度。

http://www.lryc.cn/news/605761.html

相关文章:

  • 以AI大模型重构教育新生态,打造“教-学-练-辅-评”一体化智能平台
  • 澳交所技术重构窗口开启,中资科技企业如何破局?——从ASX清算系统转型看跨境金融基础设施的赋能路径
  • matlab - 算4个数的加减法
  • [mind-elixir]Mind-Elixir 的交互增强:单击、双击与鼠标 Hover 功能实现
  • 协同测试总结(电台/WIFI/ID/固定端口设置和开机自启)
  • CentOS 6.10 上安装 GCC 7+
  • PHP 与 MySQL 详解实战入门(1)
  • PHP 5.5 Action Management with Parameters (English Version)
  • 通义千问Qwen3-30B-A3B-Thinking-2507技术解析:推理模型的工程实践突破
  • 常见的中间件漏洞如tomcat,weblogic,jboss,apache靶场攻略
  • 基于瑞芯微SoC的产品开发流程详解
  • 18650圆柱电池自动面垫机:自动化生产的效率革命
  • 人工智能之数学基础:频率和概率之间的关系
  • Java项目:基于SSM框架实现的小区物业管理系统【ssm+B/S架构+源码+数据库+毕业论文+开题报告+任务书+远程部署】
  • JS常见问题
  • BatchNorm 一般放在哪里?
  • InfluxDB 与 Python 框架结合:Django 应用案例(二)
  • DoRA详解:从LoRA到权重分解的进化
  • 小杰数据结构(three day)——静以修身,俭以养德。
  • 【Linux系统】库的制作与原理
  • 【数据结构】算法代码
  • 渗透RCE
  • TS 常用类型与语法
  • Cesium 快速入门(六)实体类型介绍
  • Jmeter 性能测试常用图表、服务器资源监控
  • C语言指针(三):数组传参本质、冒泡排序与二级指针详解
  • FISCO BCOS Gin调用WeBASE-Front接口发请求
  • [硬件电路-111]:滤波的分类:模拟滤波与数字滤波; 无源滤波与有源滤波;低通、带通、带阻、高通滤波;时域滤波与频域滤波;低价滤波与高阶滤波。
  • 操作系统数据格式相关(AI回答)
  • 无人船 | 图解基于LQR控制的路径跟踪算法(以欠驱动无人艇Otter为例)