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)
当 setState 或 props 变化触发更新时,双缓存机制正式发挥威力:
- 克隆根节点:React 会基于当前的
current树,克隆出根节点,并以此构建一颗全新的workInProgress树。 - 异步可中断构建:React 开始“递”阶段(Reconciler 执行)。它会深度遍历
workInProgress树,调用组件render函数,计算 Diff,并打上副作用标记(如 Placeholder, Update, Delete)。由于workInProgress是内存中的副本,这个构建过程完全可以被中断、暂停或放弃(利用浏览器空闲时间),而屏幕上的current树依然保持着旧界面,用户不会看到半成品的 UI。 - 完成构建:当整棵
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. 经典面试点睛(冷知识)
当面试官问到 fiberRootNode 和 hostRootFiber 时,你可以补充:Fiber 的双缓存体现在 fiberRootNode(根节点)上挂载的 current 指针,它时刻指向当前屏幕对应的那棵 Fiber 树,而每次更新时,React 都会调用 createWorkInProgress 基于 current 生成新树,并在提交阶段交换指针。