什么是 React Fiber
2025-06-05 14:51
什么是 React Fiber
Fiber 是 React 16 以后新引入的架构,它不只是描述虚拟 DOM,而是将每一个节点抽象成“工作单元”,同时保存组件的状态、任务进度、优先级。
在 React 15 及以前,每次更新时 React 会重新生成一棵完整的虚拟 DOM 树,再与上一棵树进行 Diff,找出差异进行批量更新。这种方式有两个问题:
- 递归更新过程是同步执行,无法中断,树一旦大了,就会造成卡顿。
- 无法为不同更新分配优先级,比如用户输入与低优先级动画更新不能调度。
为了解决这个问题,React 16 开始引入Fiber 架构。
Fiber 其实就是一个比“虚拟 DOM 节点”更强大的数据结构:
- 它描述了当前节点(类型、props 等)。
- 它保存了上一次渲染的节点(alternate)。
- 它记录了这次更新的状态(是否需要插入、更新、删除)。
- 它是调度和中断的最小工作单元。
可以简单理解为:Fiber = 虚拟节点 + 更新状态 + 调度信息
Fiber 和虚拟 DOM 有什么区别?
很多人最容易混淆 Fiber 和虚拟 DOM。实际上它们是两个层面的概念:
- 虚拟 DOM:只是一棵树,负责描述 UI 结构。
它轻量,更新时每次都生成新的描述。JAVASCRIPT{ type: 'div', props: { className: 'header' }, key: null }
- Fiber:是一种带有指针和状态的工作单元,既负责描述,也记录“进度”,支持中断和恢复。
Fiber 树结构是带链表指针的虚拟 DOM 树,React 基于它实现了调度、优先级控制和可中断渲染。JAVASCRIPT{ type: 'div', // 节点类型 stateNode: 真实 DOM 或组件实例, // 真实节点引用 return: 父 Fiber, // 父节点指针 child: 第一个子 Fiber, // 第一个子节点指针 sibling: 下一个兄弟 Fiber, // 下一个兄弟节点指针 alternate: 上一次的 Fiber, // 上一次渲染的 Fiber 指针(用于对比) flags: 本次更新需要执行的操作 // 副作用标记 }
为什么 Fiber 要用链表指针?
在 React 15 中,Diff 和更新过程是靠递归实现的。递归调用依赖调用栈来维护上下文。 这样有两个缺点:
- 递归过程同步且不可中断,会阻塞主线程。
- 中间状态都存储在调用栈,React 无法灵活管理任务调度。 Fiber 将树改造为带有指针的链表结构,包含:
child
: 指向第一个子节点;sibling
: 指向下一个兄弟;return
: 指向父节点; 这样设计的好处是:- React 不依赖调用栈,而是通过指针灵活遍历 Fiber 树。
- 可以在任何时刻暂停遍历,保存当前 Fiber 节点状态,稍后恢复继续。
- 支持实现 React 的时间切片(Time Slicing)和并发渲染(Concurrent Rendering)。
Fiber树 ≈ 带链表指针的虚拟DOM树。 这样,每个Fiber就是一个“最小可调度工作单元”。

Fiber 的核心价值
为什么 React 要做这么复杂的设计?主要是为了解决三件事:
- 中断和恢复
- 将更新任务拆分为最小工作单元 Fiber。
- 每处理一个 Fiber,都可以暂停让出时间给浏览器。
- 避免主线程长时间阻塞,保证 UI 流畅。
- 优先级调度
- 每个Fiber携带 lanes(优先级)
- 高优先级任务(如用户输入)先执行,低优先级任务(动画、日志)可延后。
- React 18 进一步强化优先级调度,实现并发模式。
- 双缓存机制
- 维护两棵 Fiber 树:current 指向已渲染的 Fiber 树,workInProgress 指向正在构建的新 Fiber 树。
- 更新时先在 workInProgress 树上操作,更新完成后整体切换为新的树。
- 这样避免更新过程直接影响当前渲染,保证一致性。
可以理解为: React Fiber 让“描述”和“执行”完全融合,也让更新过程变得可中断、可恢复、可调度。
Fiber树是如何生成的?
在了解React Diff之前,我们先要明白:Fiber树不是一次性生成,而是在渲染时动态创建和更新的。React 16+ 的整个更新过程,分为两个阶段:
- 调和阶段(Reconciliation / Render Phase)
- 主要目标:
- 创建新的 Fiber 树
- 复用旧的 Fiber 节点
- 比对新旧树,标记差异
- 这个阶段可以被中断,也可以多次执行(支持时间切片)
- 最后生成一棵工作中的Fiber树 (workInProgress)
- 主要目标:
- 提交阶段(Commit Phase)
- 把收集的副作用一次性提交到DOM
- 分为三步:
beforeMutation
(快照阶段)mutation
(执行DOM操作)layout
(执行生命周期)
- 这个阶段不能中断,必须同步执行。
一句话理解:调和阶段负责「计划」,提交阶段负责「落实」。
Fiber树的双缓存机制
React在更新时,实际上会同时维护两棵Fiber树:
-
current Fiber树
- 当前屏幕上渲染的那一棵
- 存储「上一次渲染的状态」
-
workInProgress Fiber树
- 本次更新要生成的新Fiber树
- 所有Diff、状态更新、优先级,都在这里操作
- 最终提交后,这棵树会变成新的current

- React需要先在内存里把新的Fiber树准备好
- 等所有比对都完成,再一次性把变更提交
- 避免在「生成树」过程中去操作DOM,保证一致性
Fiber树的生成流程
整个Fiber树的生成采用深度优先遍历(DFS),主要分两步:
- beginWork
- 进入节点,处理当前更新逻辑
- 判断要不要复用旧Fiber
- 创建新的子Fiber
- 返回下一个要处理的子Fiber
- completeWork
- 子节点遍历完成后回到当前节点
- 确定副作用(插入、更新、删除)
- 把副作用链表传给父节点 整个过程可以这样理解:
「先往下创建树,回溯时把工作都收集好。」 Fiber树的生成过程是基于深度优先遍历,由两个核心函数驱动:
beginWork
:处理当前 Fiber 节点,生成或复用子 Fiber。completeWork
:当所有子 Fiber 处理完毕后,完成当前 Fiber 的副作用收集。 这个过程类似于递归遍历一棵树:
- 调用
beginWork
,尝试生成当前节点的子 Fiber,返回第一个子节点 Fiber。 - 如果有子节点,则继续递归
beginWork
。 - 如果没有子节点或者子节点处理完成,则回溯执行
completeWork
,标记本节点需要的副作用。 - 回溯时,如果当前节点有兄弟节点,切换去处理兄弟节点的
beginWork
。 - 直到回溯到根节点,整个 Fiber 树构建完成。
JAVASCRIPTfunction performUnitOfWork(fiber) { // 处理当前Fiber,创建/复用子Fiber const next = beginWork(fiber); if (next !== null) { // 递归往下遍历子节点 return next; } // 没有子节点或子节点已处理完,开始回溯 let node = fiber; while (node !== null) { completeWork(node); // 标记副作用 if (node.sibling !== null) { // 如果有兄弟节点,处理兄弟节点 return node.sibling; } node = node.return; // 回到父节点继续回溯 } return null; // 整棵树遍历完成 }
这段代码体现了 Fiber 树的深度优先遍历和回溯过程,保证每个节点的副作用能被完整处理并传递。
flags 标记的副作用
每个 Fiber 节点有一个 flags 字段,表示本次更新需要执行的操作类型:
Placement
:节点需要插入到 DOM。Update
:节点属性或状态更新,需要修改 DOM。Deletion
:节点需要从 DOM 删除。React
在提交阶段会根据 flags 批量执行这些操作,保证 DOM 的高效更新。
总结
React Fiber 是对传统虚拟 DOM 的重构与升级,它将渲染过程拆分为可中断的最小任务单元,支持优先级调度和时间切片,极大提升了 React 的响应能力和用户体验。 通过 Fiber 树,React 能够灵活地控制渲染进度,实现并发渲染,保证高优先级任务优先执行,并且维护双缓存机制保证 UI 的一致性。 Fiber 是 React 现代架构的核心,理解它有助于深入掌握 React 的更新原理和性能优化。