Fiber架构

124 阅读6分钟

Fiber 是 React 16 引入的​​核心调度机制​​,它本质上是一个 ​​JavaScript 对象(JS Object)​​,但比普通的虚拟 DOM 多了很多关键属性,比如:child、return、sibling、effectTag、priority、expirationTime,用这些属性来支持 ​​增量渲染(分片更新)、任务优先级调度、可中断/恢复渲染​​ 这些高级功能。


​Fiber 和普通虚拟 DOM 的区别​

特性普通虚拟 DOM(旧版 React)Fiber 节点(React 16+)
​本质​一个 JS 对象,描述 UI 结构也是一个 JS 对象,但额外增加了 ​​调度、任务管理​​ 相关的属性
​作用​只是描述 UI 应该长什么样不仅描述 UI,还管理 ​​如何更新、何时更新、更新优先级​
​结构​简单的树状结构(递归遍历)​链表结构​​(child、return、sibling 指针,支持非递归遍历)
​更新方式​​同步递归​​(一旦开始就卡住,无法中断)​异步分片​​(可暂停、恢复、优先级调度)
​关键属性​type(组件类型)、props(属性)、children(子节点)​额外增加了:​​ ✅ child(第一个子节点) ✅ return(父节点) ✅ sibling(兄弟节点) ✅ effectTag(标记更新类型:插入/更新/删除) ✅ priority(任务优先级) ✅ expirationTime(过期时间,用于调度)

源码里FiberNode的结构


function FiberNode(
  this: $FlowFixMe,
  tag: WorkTag,
  pendingProps: mixed,
  key: null | string,
  mode: TypeOfMode,
) {
  // 基本属性
  this.tag = tag; // 描述此Fiber的启动模式的值(LegacyRoot = 0; ConcurrentRoot = 1)
  this.key = key; // React key
  this.elementType = null; // 描述React元素的类型。例如,对于JSX<App />,elementType是App
  this.type = null; // 组件类型
  this.stateNode = null; // 对于类组件,这是类的实例;对于DOM元素,它是对应的DOM节点。

  // Fiber链接
  this.return = null; // 指向父Fiber
  this.child = null; // 指向第一个子Fiber
  this.sibling = null; // 指向其兄弟Fiber
  this.index = 0; // 子Fiber中的索引位置

  this.ref = null; // 如果组件上有ref属性,则该属性指向它
  this.refCleanup = null; // 如果组件上的ref属性在更新中被删除或更改,此字段会用于追踪需要清理的旧ref

  // Props & State
  this.pendingProps = pendingProps; // 正在等待处理的新props
  this.memoizedProps = null; // 上一次渲染时的props
  this.updateQueue = null; // 一个队列,包含了该Fiber上的状态更新和副作用
  this.memoizedState = null; // 上一次渲染时的state
  this.dependencies = null; // 该Fiber订阅的上下文或其他资源的描述

  // 工作模式
  this.mode = mode; // 描述Fiber工作模式的标志(例如Concurrent模式、Blocking模式等)。

  // Effects
  this.flags = NoFlags; // 描述该Fiber发生的副作用的标志(十六进制的标识)
  this.subtreeFlags = NoFlags; // 描述该Fiber子树中发生的副作用的标志(十六进制的标识)
  this.deletions = null; // 在commit阶段要删除的子Fiber数组

  this.lanes = NoLanes; // 与React的并发模式有关的调度概念。
  this.childLanes = NoLanes; // 与React的并发模式有关的调度概念。

  this.alternate = null; // Current Tree和Work-in-progress (WIP) Tree的互相指向对方tree里的对应单元

    // 如果启用了性能分析
  if (enableProfilerTimer) {
    // ……
  }

    // 开发模式中
  if (__DEV__) {
    // ……
  }
}

Fiber 是怎么工作的?​

  1. ​第一步:生成新的虚拟 DOM(JSX → Virtual DOM)​

    • 当用户交互(如点击、输入)发生时,React 会先生成新的 ​​虚拟 DOM(JS 对象)​​,描述 UI 应该变成什么样子。
  2. ​第二步:对比新旧虚拟 DOM(Diffing Algorithm)​

    • React 会比较 ​​新的虚拟 DOM​​ 和 ​​旧的虚拟 DOM​​,找出哪些部分发生了变化(比如某个组件的 props变了,或者某个 DOM 节点被删除了)。
  3. ​第三步:生成 Fiber 树(构建 Fiber 节点)​

    • React 会把 ​​虚拟 DOM 转换成 Fiber 节点​​(也就是给每个虚拟 DOM 节点加上 ​​调度相关的属性​​,比如 childreturnsiblingeffectTag等)。
    • 这个过程叫做 ​​"Reconciliation"(协调)​​,React 会 ​​遍历 Fiber 树​​,找出哪些 Fiber 节点需要更新(比如新增、修改、删除)。
  4. ​第四步:调度更新(Scheduler)​

    • React 16 引入了 ​​调度器(Scheduler)​​,它会根据 ​​优先级​​(比如用户交互 > 动画 > 数据加载)决定 ​​先更新哪些 Fiber 节点​​。
    • 如果某个更新被中断(比如用户突然滚动页面),React 可以 ​​暂停当前任务,先处理更高优先级的任务​​,等浏览器空闲了再回来继续。
  5. ​第五步:提交更新(Commit Phase)​

    • 最后,React 会把所有 ​​标记了 effectTag(如 PLACEMENTUPDATEDELETION)的 Fiber 节点​​,​​批量更新到真实 DOM​​,这样页面就能高效、流畅地变化了。

  • 双缓冲技术  React在更新时,会根据现有的Fiber树(Current Tree)创建一个新的临时树(Work-in-progress (WIP) Tree),WIP-Tree包含了当前更新受影响的最高节点直至其所有子孙节点。Current Tree是当前显示在页面上的视图,WIP-Tree则是在后台进行更新,WIP-Tree更新完成后会复制其它节点,并最终替换掉Current Tree,成为新的Current Tree。因为React在更新时总是维护了两个Fiber树,所以可以随时进行比较、中断或恢复等操作,而且这种机制让React能够同时具备拥有优秀的渲染性能和UI的稳定性。

  • State 和 Props:memoizedPropspendingProps 和 memoizedState 字段让React知道组件的上一个状态和即将应用的状态。通过比较这些值,React可以决定组件是否需要更新,从而避免不必要的渲染,提高性能。

  • 副作用的追踪flags 和 subtreeFlags 字段标识Fiber及其子树中需要执行的副作用,例如DOM更新、生命周期方法调用等。React会积累这些副作用,然后在Commit阶段一次性执行,从而提高效率。


​为什么 Fiber 要这么设计?​

  • ​旧版 React(15 及之前)​​ 的更新是 ​​同步递归的​​,一旦开始渲染,就会一直执行到完成,​​如果组件树很大,就会导致页面卡顿(比如输入框输入时卡顿)​​。
  • ​Fiber 架构(16+)​​ 把渲染过程 ​​拆分成多个小任务​​,可以 ​​暂停、恢复、优先级调度​​,让 React 能更智能地管理 UI 更新,​​避免长时间阻塞主线程​​,从而提升用户体验。

​总结​

  • ​Fiber 就是一个 JS 对象​​,但它比普通虚拟 DOM ​​多了调度相关的属性​​(如 childreturnsiblingpriority)。
  • ​Fiber 的核心作用​​ 是让 React 能 ​​增量渲染、任务优先级调度、可中断/恢复更新​​,从而让页面更流畅。
  • ​整个流程​​:​​用户交互 → 生成新虚拟 DOM → 对比新旧 DOM → 生成 Fiber 树 → 调度更新(优先级) → 提交到真实 DOM​

一、架构定位(核心定义)

image.png

二、诞生背景(痛点拆解)

image.png

三、核心原理(三大支柱)

1. Fiber 节点(工作单元)

image.png

2. 双缓存机制(树切换逻辑)

image.png

3. 调度机制(时间切片 + 优先级)

image.png