react通过fiber树双缓存机制(current与workinprogress)实现可中断渲染,真实dom仅在commit阶段批量创建更新,保障ui一致性与性能。
react 并不直接在内存中构建真实 dom 树再挂载——它构建的是 fiber 树(一种带调度信息的虚拟结构),而真实 dom 的创建和更新由 renderer 在 commit 阶段完成。所谓“在内存中构建 dom 树再挂载”,本质是利用双缓存机制,在内存中安全、高效地组织好新 ui 的完整描述(即 workinprogress fiber 树),等全部准备就绪后,才一次性切换并触发真实 dom 操作。
双缓存不是操作真实 DOM,而是管理 Fiber 节点
React 的双缓存对象是两棵 Fiber 树,不是两棵真实 DOM 树:
-
current 树:对应当前屏幕上正在显示的 UI,其每个 Fiber 节点的
stateNode字段已指向真实 DOM 元素(挂载后) -
workInProgress 树:纯内存结构,节点的
stateNode初始为null或复用旧值,它只负责承载更新逻辑、副作用标记(flags)、优先级等调度信息 - 真实 DOM 不会在 render 阶段被创建或修改;所有 DOM 创建(
createInstance)、插入(appendInitialChild)、更新(updateHostText)都严格发生在 commit 阶段,且仅基于 workInProgress 树中已标记的变更
挂载流程:从空 Fiber 到真实 DOM 的三步落地
以首次 ReactDOM.createRoot(rootNode).render(<app></app>) 为例:
-
初始化 fiberRoot 和 rootFiber:生成
fiberRootNode(全局根容器)和rootFiber(应用入口 Fiber),此时fiberRoot.current === rootFiber,但rootFiber.stateNode === null -
Render 阶段构建 workInProgress 树:调用
prepareFreshStack创建新的workInProgress根节点,深度遍历 JSX,逐层调用reconcileChildren构建子 Fiber 链表;对每个 HostComponent(如<div>),生成 Fiber 节点但<strong>不创建真实 DOM</strong> <li> <strong>Commit 阶段批量挂载</strong>:进入 <code>commitMutationEffects,按 effect list 顺序执行:- 对
Placement标记的节点,调用createInstance(type, props)创建真实 DOM 元素 - 递归调用
appendInitialChild将子节点挂载进父 DOM - 最后将顶层容器(如
#root)的firstChild设为新构建的 DOM 树根
- 对
- 如果边计算边改 DOM,中间状态可能被用户看到(闪烁、错位),或被并发事件打断导致 DOM 与 React 状态不一致
- Fiber 节点通过
alternate双向链接,使 React 能随时丢弃未完成的 workInProgress 树,回到 current 树继续渲染,这是时间切片(Time Slicing)的基础 - 真实 DOM 操作昂贵且不可逆;Fiber 是轻量 JS 对象,构建、丢弃、复用成本极低
-
合理使用
key:确保列表项复用准确,减少不必要的 Fiber 创建和 DOM 替换 -
避免内联函数/对象作为 props:防止
memoizedProps总是变化,导致本可复用的 Fiber 被强制重建 -
用
useMemo/useCallback缓存派生数据:降低beginWork中的计算开销,加快 workInProgress 树构建速度 -
拆分大组件 +
Suspense:让部分 workInProgress 子树延迟构建,释放主线程,体现双缓存的可中断优势
为什么不能跳过 Fiber 直接操作 DOM?
双缓存的价值不在“预建 DOM”,而在保障一致性与可中断性:
你真正能控制的“内存构建”环节
开发者可通过以下方式配合双缓存机制提升效率:










