Fiber架构

353 阅读6分钟

Fiber架构与双缓存机制

Fiber架构的基本概念

什么是Fiber

在React中,Fiber是一种用于描述组件树的数据结构,它代表了一种可中断的,可恢复的渲染任务。传统的渲染任务一旦开始,无法中断,直至渲染完成或发生错误,导致页面卡顿。Fiber将渲染任务分割成多个小任务,在渲染过程中可以中断,可重新排序调度任务,使React对浏览器的空闲时间进行了更充分的利用,提升了性能和用户体验。

Fiber树🌲

Fiber树的创建过程
  1. React根据JSX生成虚拟DOM树。
  2. 对每个虚拟DOM节点生成对应的Fiber节点,构建起Fiber树的层级结构。
  3. 执行初次渲染,React从根节点开始递归遍历Fiber树,执行组件的渲染,将组件渲染到DOM上。
Fiber树结构

Fiber节点结构

  1. 每个节点包含
    • 指针(child、sibling、return)
    • 属性(如DOM信息、任务调度信息)
    • 状态信息
  2. 这些指针将节点连接成一个单链表结构、允许react通过循环遍历,遍历到每个节点。

Fiber树结构

  1. 以单链表形式组织,父节点指向第一个子节点,子节点通过sibling指针连接兄弟节点。
  2. 这种机制结构避免了传统树结构的递归遍历,减少栈溢出风险,提升性能。
Fiber树的更新
  1. 触发更新
  2. 生成新的虚拟DOM树
  3. 对比两棵虚拟DOM树的差异
  4. 根据协调算法的结果,React 会更新 Fiber 树的相应节点,执行组件的生命周期方法和渲染函数,将更新后的组件树渲染到 DOM 中。
协调算法
旧的协调算法
  1. 基于虚拟DOM树的比较
    • 旧的协调算法通过深度遍历新旧虚拟DOM树,逐层比较节点的类型和属性。如果类型相同则更新属性,类型不同则销毁旧节点创建新的节点
  2. 递归处理子节点:
    • 对于有子节点的节点,递归的对子节点进行比较,直至整个DOM树被比较完。这种递归方式,在处理深层嵌套结构时有栈溢出的风险
  3. 列表遍历优化
    • 在处理列表时,旧的协调算法通过使用“key”属性来帮助识别元素的变化。通过唯一标识符"key",react能更准确的追踪元素变化,减少不必要的DOM操作
  4. 简单高效
    • 旧的协调算法在大多数情况下能表现良好,但遇到复杂嵌套结构或长列表时,可能出现性能问题 一旦开始更新,就无法中断,直到所有节点都完成更新或者发生错误。这导致在更新过程中无法处理其他任务,从而影响了用户体验。
新的协调算法:增量渲染

增量渲染的核心思想:将渲染任务分割成多个小任务,并使用任务调度器动态的调度这些任务

增量渲染的好处:使得在更新过程中可以中断,并在下一个空闲时间片段内恢复,提高了渲染的灵活性和效率。增量渲染还为react引入了一些新的特性,如时间切片(Time Slicing)和任务优先级调度,使得React应用能够更好的适应不同的网络环境和设备性能。

时间切片

React通过将渲染任务切割成小的时间片,逐帧处理,确保用户界面能够快速响应用户操作。这种技术结合了任务优先级调度和可中断恢复机制,使得复杂的应用程序能够更高效地运行。

任务优先级调度
不同优先级的任务
// 无优先级任务
export const NoPriority = 0;
// 立即执行任务
export const ImmediatePriority = 1;
// 用户阻塞任务
export const UserBlockingPriority = 2;
// 正常任务
export const NormalPriority = 3;
// 低优先级任务
export const LowPriority = 4;
// 空闲执行任务
export const IdlePriority = 5;

在 React 中,任务被划分为不同的优先级,以便根据任务的重要性进行调度。通常情况下,React 将任务分为以下几个优先级:

  • 同步任务:最高优先级的任务,通常用于处理用户交互事件和页面加载过程中的同步操作。
  • 异步任务:中等优先级的任务,包括普通的更新任务和网络请求等异步操作。
  • 空闲任务:最低优先级的任务,通常用于执行一些不紧急的任务,如日志记录或统计信息收集等。
调度器的工作方式

调度器会根据任务优先级和类型,动态的安排任务的执行顺序。调度器会监视浏览器的空闲时间,并根据当前在任务队列中的任务优先级决定在何时执行哪些任务。

Fiber架构的工作原理

双缓存机制

Fiber的双缓存机制是React16引入的核心优化技术之一,旨在提升渲染性能和用户体验。

双缓存机制的定义

Fiber双缓存机制通过维护两棵Fiber树来实现高效的渲染和更新

  • Current Fiber树:当前屏幕上显示的真实UI对应的Fiber树。
  • WorkInProgress Fiber树:正在内存中构建的新Fiber树,用于下一次的渲染
  • 这两棵树通过alternate属性相互关联,即
    • currentFiber.alternate === workInProgressFiber
    • workInProgressFiber.alternate === currentFiber

React应用的根节点通过使current指针在不同Fiber树rootFiber间切换来完成current Fiber树指向的切换。

双缓存机制的工作原理
  1. 首次渲染(Mount)
    • 创建初始的Fiber Root节点,并生成初始的Current Fiber树
    • 在内存中构建workInProgress Fiber树,并通过alternate属性与currentFiber树相关联
  2. 更新阶段(Update)
    • 根据新的React节点与current Fiber树生成新的workInProgress Fiber树
    • 通过深度优先遍历和Diff算法,比较新旧节点,生成更新标记(删除、移动、插入等)
    • 构建完成后workInProgress Fiber树替换current Fiber树完成DOM更新
  3. 交替切换
    • 每次更新后workInProgress Fiber树成为新的current Fiber树,而旧的current树则成为下一次更新的workInProgress
双缓存机制的优势
  1. 提升渲染性能:在内存中构建新的树,避免在屏幕上直接渲染导致闪烁和性能问题。
  2. 支持任务分片:将渲染任务切割成小块,逐帧处理,确保用户界面快速响应。
  3. 优先级调度:根据任务优先级决定执行性顺序,确保高优先级任务及时响应。
  4. 可恢复中断:允许在渲染过程中中断并恢复任务,优化用户体验。
Fiber双缓存机制的实现细节
  • 交替属性:workInProgress Fiber树和current Fiber树通过alternate连接确保快速切换
  • 根节点切换:React应用的根节点通过current指针在不同Fiber树的rootFiber之间切换,完成树的替换
  • 任务调度:Fiber通过Scheduler API管理任务,确保渲染任务在不影响用户体验的情况下高效执行

手绘Fiber树构建流程图

graph TD
初始化根节点fiberRootNode和rootFiber--> 创建CurrentFiber--> 进入渲染阶段--> 在内存中构建WorkInProgressFiber树--> 进行Diffing比较新旧节点和复用旧节点--> 构建好新的WorkInProgressFiber树--> 进入体检阶段commit--> 渲染为真实DOM节点--> 替换CurrentFiber树fiberRootNode.current指向新的WorkInProgressFiber树--> 完成构建