Skip to main content

React Fiber 双缓存机制

React Fiber 双缓存(Double Buffering)是 React 16 之后协调引擎(Reconciler)的核心运行机制。它并非指浏览器中的 DOM 缓存,而是指内存中两棵 Fiber 树的交替复用

它的核心目的是:在内存中提前完成高成本的 DOM 树计算,通过“指针切换”瞬间完成视图更新,从而为可中断渲染(Time Slicing)提供基础。

为了让你透彻理解,我从“数据结构”到“工作流程”逐步拆解:

1. 两棵树的定义

在 React 内存中,永远同时维护着两棵 Fiber 树:

  • current 树(当前树):代表当前屏幕上已经渲染好的真实 UI 所对应的 Fiber 节点结构。它关联着实际的 DOM 实例。
  • workInProgress 树(工作树):代表正在内存中构建、尚未渲染到屏幕的 Fiber 节点结构。它是未来要呈现的新视图。

这两棵树通过 Fiber 节点上的 alternate 属性相互引用(互相指向对方的副本)。

2. 核心机制:双缓冲的运转流程

第一阶段:挂载(Mounting)

  • React 首次执行 ReactDOM.render 时,在内存中创建根节点的 Fiber 树(即 workInProgress 树)。
  • 构建完成后,React 会将这棵树对应的 DOM 节点一次性追加到页面上。
  • 关键动作:渲染完成后,这棵刚刚构建好的树会直接赋值给 root.current变成 current。此时 workInProgress 树为 null

第二阶段:更新(Update)

setStateprops 变化触发更新时,双缓存机制正式发挥威力:

  1. 克隆根节点:React 会基于当前的 current 树,克隆出根节点,并以此构建一颗全新的 workInProgress 树。
  2. 异步可中断构建:React 开始“递”阶段(Reconciler 执行)。它会深度遍历 workInProgress 树,调用组件 render 函数,计算 Diff,并打上副作用标记(如 Placeholder, Update, Delete)。由于 workInProgress 是内存中的副本,这个构建过程完全可以被中断、暂停或放弃(利用浏览器空闲时间),而屏幕上的 current 树依然保持着旧界面,用户不会看到半成品的 UI。
  3. 完成构建:当整棵 workInProgress 树的所有子节点都处理完毕,它就已经包含了所有最新的 DOM 结构信息和变更标记。

第三阶段:提交(Commit)—— 指针切换

这是最关键的一步,且必须是同步且不可中断的

  • React 拿到构建好的 workInProgress 树,开始“归”阶段,执行 DOM 的增删改操作。
  • 所有 DOM 变更批量应用完毕后,React 会执行一个极其轻量的操作:将根节点的 current 指针,从旧的 current 树,直接切换到这棵 workInProgress 树上
  • 切换完成workInProgress 树瞬间变为新的 current 树。与此同时,旧的 current 树变成了失活的树,等待下一次更新时被复用(作为新的 workInProgress 树的克隆模板)。

3. 为什么需要双缓存?(三大核心价值)

  • 保证视觉一致性(避免白屏/闪屏):因为 workInProgress 树完全在内存中构建,即使 JS 计算耗时、被中断,屏幕上始终展示的是完整的 current 树。只有当所有计算和 DOM 变更都确定无误后,才通过指针切换“瞬间”切换视图,绝不会出现“半截渲染”的撕裂现象。
  • 支持时间切片(Time Slicing)与 Suspense:由于 workInProgress 是独立副本,React 可以在构建过程中随时“放下”手头的工作(让出主线程给浏览器绘制),等浏览器空闲时再“拿起”继续构建。如果中途有更高优先级的更新(如用户输入),React 甚至可以放弃当前的 workInProgress 树,直接重新创建一颗新的,而旧树因未提交,直接丢弃即可,没有任何副作用。
  • 内存复用(节省性能):更新时,React 并不总是新建 Fiber 节点,而是通过 alternate 复用旧节点。它利用双缓存中的“失活树”作为“工作树”的起点,尽可能地复用原有的 Fiber 对象和 DOM 实例,只需要更新变了的那部分属性,大幅降低内存开销。

4. 对比:与浏览器的“双缓冲”异同

这是一个绝佳的类比,便于记忆:

  • 屏幕 对应 React 的 current(用户看到的)。
  • 显卡后台缓冲区 对应 React 的 workInProgress(内存中绘制)。
  • 浏览器双缓冲是硬件层面的显存地址切换;React 双缓存是内存中 JS 对象的 current 指针切换。两者本质上都是为了保证渲染的原子性与完整性

5. 经典面试点睛(冷知识)

当面试官问到 fiberRootNodehostRootFiber 时,你可以补充:Fiber 的双缓存体现在 fiberRootNode(根节点)上挂载的 current 指针,它时刻指向当前屏幕对应的那棵 Fiber 树,而每次更新时,React 都会调用 createWorkInProgress 基于 current 生成新树,并在提交阶段交换指针。