什么是Fiber?
回答这个问题需要从三个方面来理解:
- 是一种架构模式:Fiber架构。V16版本之前,React使用的 Stack 架构,V16发布之后使用的Fiber架构;
- 是一种数据类型:描述虚拟DOM的JS对象。在上篇文章虚拟DOM中提到了React在Stack架构和FIber架构实现虚拟DOM的方式是不同的,V16之后,使用了Fiber节点组成的链表实现了虚拟DOM的描述对象。
- 是一种调度单元:将整个渲染过程拆解为多个可中断、可优先级调度的“纤维”(Fiber)任务。
在上篇上篇文章虚拟DOM中也提到了虚拟DOM是描述对象是如何的, 现在就可以看看Fiber节点描述的虚拟DOM中是长什么样子的:
{
type: ComponentType, // 组件类型(函数/类)
key: string, // 同级节点唯一标识
child: Fiber, // 第一个子节点
sibling: Fiber, // 下一个兄弟节点
return: Fiber, // 父节点
pendingProps: Props, // 新传入的props
memoizedProps: Props,// 上次渲染的props
stateNode: Instance, // 组件实例或DOM节点
effectTag: number, // 标记副作用(如插入、更新、删除)
// ...其他调度相关字段(优先级、状态等)
}
Fiber通过child
、sibling
、return
形成链表树,替代了原有的树形结构,实现非递归遍历。
为什么要出现Fiber?
我们知道React使用通过操作虚拟DOM进行页面视图的更新,当我们更新一个状态去触发更新时,React需要进行寻找该节点的位置,然后去更新它。
但是 Stack 架构基于递归的协调算法来更新虚拟DOM,我们知道JS的线程和渲染线程是在同一个线程中为互斥关系,当组件树庞大时,递归更新会长时间占用主线程,这个时候渲染层面的更新就不得不长时间地等待,界面长时间不更新,会导致页面响应度变差,用户可能会感觉到卡顿。这就是Fiber架构出现的原因,旨在支持任务的中断与恢复。
Fiber 双缓冲
双缓冲是为了提升视觉流畅性,工作原理类似于显卡的工作原理:
- 前缓冲区(Front Buffer) :当前屏幕显示的图像帧。
- 后缓冲区(Back Buffer) :后台计算新图像帧的临时区域。
- 互换机制:当后缓冲区完成新帧计算后,通过缓冲区交换(Swap) 瞬间替换前缓冲区内容。
这样达到效果是:一方面避免用户看到渲染中间态(如闪烁、撕裂);另一方面将耗时的渲染计算隐藏在后台,保证画面连续流畅。
React 将双缓冲思想深度融入 Fiber 中,通过双 Fiber 树实现无感知的平滑更新,具体实现:
-
双树共存
- Current Tree:与当前 UI 完全对应的 Fiber 树,代表已渲染的视图状态。
- WorkInProgress Tree:内存中构建的新 Fiber 树,承载下一次更新的计算任务。
-
树间关联
- 每个 Fiber 节点通过
alternate
属性与另一棵树的对应节点互相引用:
- 每个 Fiber 节点通过
// Current Fiber 节点
currentFiber.alternate = workInProgressFiber;
// WorkInProgress Fiber 节点
workInProgressFiber.alternate = currentFiber;
// 这种双向指针设计使得状态复用、增量更新成为可能。
-
渲染流程
- 构建阶段:在 WorkInProgress Tree 上执行组件渲染、Diff 计算,生成副作用链表(Effect List)。
- 提交阶段:锁定两棵树,将 WorkInProgress Tree 一次性切换为 Current Tree,同步更新 DOM。
- 循环往复:完成提交后,旧的 Current Tree 转为新 WorkInProgress Tree 的初始状态。
双缓存可以让计算过程完全在内存中的 WorkInProgress Tree 完成,用户始终感知稳定的 Current Tree 视图,视觉上不会出现撕裂的效果。