React面试宝典【Part3:Fiber架构 + Diff算法】

2026-08-03 React,面试

三、渲染原理:Fiber架构 + Diff算法

1. React16为什么推出Fiber架构?

老架构:Stack Reconciler,同步递归渲染,不可中断;组件树庞大时阻塞主线程,页面卡顿。
Fiber目标:

  1. 时间切片,任务可中断、恢复、优先级调度
  2. 将递归改为链表遍历(child/sibling/return指针)
  3. 拆分为两大阶段:Render阶段 + Commit阶段
    Render阶段(可中断!纯内存计算,无DOM操作)
    构建Fiber树、执行Diff、标记更新副作用(Placement/Update/Deletion)
    Commit阶段(不可中断!操作真实DOM)
    一次性执行所有DOM增删改;分为before mutation → mutation → layout

详解

1. 解决旧架构(Stack Reconciler)的性能瓶颈

  • 旧版 React 递归更新虚拟 DOM 是同步、不可中断
  • 一旦开始 diff,就会一直占用主线程,直到执行完毕
  • 当组件树庞大时,会阻塞浏览器渲染、交互、动画,导致页面卡顿、掉帧

2. 实现可中断、可恢复、可优先级调度的渲染
Fiber 把 diff 过程拆分为小任务单元,支持:

  • 可中断:执行一段时间就让出主线程
  • 可恢复:下次继续执行,不从头再来
  • 可插队:高优先级任务(输入、点击)可以打断低优先级任务
  • 可废弃:可直接放弃旧更新,执行新更新

3. 为并发模式(Concurrent Mode)铺路
Fiber 是 React 并发能力的底层基础

  • 支持 Suspense
  • 支持 useTransition、useDeferredValue 等优先级调度
  • 让 React 能根据设备性能、任务类型智能调度更新

4. 更精细的生命周期与副作用调度

  • 把渲染分为 render 阶段(可中断)commit 阶段(不可中断)
  • render 阶段:diff、构建 Fiber 树
  • commit 阶段:真实 DOM 更新、执行 useEffect/useLayoutEffect

总结

旧架构递归同步阻塞主线程,Fiber 把更新拆分为可中断的小任务,实现时间分片与优先级调度,从根本解决大型应用卡顿问题,并为 React18 并发特性打下基础。


2. Diff算法三大策略(协调Reconciliation/ ˌrekənsɪliˈeɪʃ(ə)n /)

  1. 只同级比较,不跨层级移动节点;跨层级直接销毁重建
  2. 同类型节点:更新属性;不同类型:直接销毁重建
  3. key作为节点唯一标识,实现列表节点复用

面试官追问:能不能实现跨层级Diff?可以,但算法复杂度O(n³),性能无法接受,React选择工程权衡。

详解

1. 同级比较,不跨层级 Diff

  • 只对同一层级的节点进行对比
  • 若节点类型变了,直接销毁重建,不继续往下 diff
  • 避免 O(n³) 复杂度,降到 O(n)

2. 不同类型节点,生成不同树

  • 标签名/组件类型不同 → 认为是完全不同的树
  • 直接删除旧节点,创建新节点,不做复用
  • 防止复杂结构对比,大幅提速

3. 列表 Diff 通过 key 区分节点

  • 列表渲染必须带 key
  • React 根据 key 匹配新旧节点,实现移动、复用、删除
  • 避免盲目重建所有列表项

总结

只同级 diff、类型不同就重建、列表靠 key 复用。
目的:把暴力 Diff 从 O(n³) 优化到 O(n)。


3. React 协调(Reconciler)完整流程(Fiber 版)

触发更新(setState/useState)→ 创建更新任务 → Scheduler调度 → Render(构建Fiber+diff打标记)→ Commit阶段执行DOM更新

详解

一、触发更新

  • setState、useState dispatch、forceUpdate、ReactDOM.render
  • 标记对应 Fiber 节点为 dirty(待更新)
  • 进入调度阶段

二、调度阶段(Scheduler)

  • 根据任务优先级(高:输入/点击;低:列表渲染)进行调度
  • React18 基于 时间分片,每帧让出主线程,避免卡顿
  • 高优先级任务可插队、打断低优先级任务

三、协调阶段(Render 阶段)——可中断、可恢复
深度遍历 Fiber 树,执行:

  1. beginWork(向下遍历)

    • 创建/更新 Fiber 节点
    • 执行组件 render,生成新 VDOM
    • Diff 子节点,打上 effectTag(新增/删除/更新)
  2. completeWork(向上归并)

    • 处理 props、style、event
    • 收集副作用(Effect List)
    • 形成一条单向副作用链表,供 commit 阶段批量执行

特点:

  • 可中断、可恢复、可重制
  • 不操作真实 DOM
  • 生命周期/Hook 在此阶段可能被多次调用

四、提交阶段(Commit 阶段)——同步不可中断
一次性批量更新 DOM,分三步:

  1. commitBeforeMutationEffects

    • 执行 DOM 更新前操作
    • 处理 useLayoutEffect 清理
  2. commitMutationEffects

    • 操作真实 DOM:增删改
    • 重置文本、属性、样式
    • 切换 ref
  3. commitLayoutEffects

    • DOM 已更新,执行布局副作用
    • 执行 useLayoutEffect 回调
    • 最后执行 useEffect(异步调度)

五、结束

  • 清空副作用队列
  • 组件更新完成
  • 进入下一帧渲染

总结

  1. 触发更新 → 标记 Fiber 为脏
  2. 调度优先级 → 时间分片
  3. Render 协调:beginWork 遍历 + Diff 收集副作用,可中断
  4. Commit 提交:批量同步更新 DOM,执行 Layout/Effect
  5. 完成渲染