React学习-核心概念及渲染过程的理解

20 阅读8分钟

一、什么是双缓冲模式:

现实生活中的例子,你去看话剧,需要无间断专场,就需要准备两个舞台场景,例如室内切换到到室外;

工作人员需要准备两个场景,室内场景表演完成后熄灯,演员直接走入第二个 室外场景;

对应react中则是:

current树 与 workInProgress树 可以对标 “双缓冲” 模式下的两套缓冲数据

当 current树呈现在用户眼前时,所有的更新都会由 workInProgress 树来承接

workInProgress树将会在用户看不到的地方(内存里)悄悄地完成所有改变

双缓冲如何工作?

1. 初始化

  • 应用首次渲染时,只有一棵 current 树。
  • 当发生更新(如 setState),React 会创建一棵新的 workInProgress 树。

2. 构建新树

  • React 在 workInProgress 树上逐步计算新的 Fiber 节点(可中断、可恢复)。
  • 这个过程不会影响当前显示的 current 树,用户界面保持稳定。

3. 提交(Commit)

  • workInProgress 树构建完成且无错误,React 会原子性地workInProgress 树切换为 current 树。

  • 同时,原来的 current 树被回收,作为下一次更新的 workInProgress 树的“缓冲池”(复用节点,减少内存分配)。

    🔄 交替复用:两棵树的角色在每次更新后互换,形成循环利用。

总结:

  • React 双缓冲 = 两棵 Fiber 树(current + workInProgress)交替使用
  • 目的是实现 安全、高效、可中断的异步渲染
  • 是 Fiber 架构和并发特性的基石之一
  • 对开发者透明,但理解它有助于深入掌握 React 性能优化原理

二、时间切片

同步渲染模式下的render 阶段是一个同步的、深度优先搜索的过程

同步状态的调用栈是这样的:

1.png

图中有一个很长的task任务,这就是同步带来的问题,它可能会阻塞浏览器,出现卡顿;

当使用异步并发时:

2.png

现在变为多个 task,一个大概在5ms左右;全部加起来和上面时间是差不多的;

但是中间的时间间隙留给了浏览器空闲选择,是否让出主线程;

切片时长是由:react根据浏览器的帧率 动态计算出来的,与浏览器的性能有关;

时间切片的核心思想

利用浏览器每一帧的空闲时间,分批处理 React 更新工作

浏览器一帧(通常 16.7ms)的工作流程大致如下:

[ 处理用户输入 ][ 执行 JS ][ 样式计算 ][ 布局 ][ 绘制 ][ 合成 ]

React 的时间切片会在 JS 执行阶段 中:

  1. 检查当前帧(每帧 16.7ms左右)还剩多少时间;
  2. 如果有足够时间(比如 >5ms),就处理一小部分 Fiber 节点;
  3. 如果时间快用完,就暂停工作,把控制权交还给浏览器;
  4. 下一帧继续处理剩余工作。

这个过程由 Scheduler(调度器) 控制,基于 MessageChannelpostMessage 实现微任务调度(比 setTimeout 更精准)。

总结:

  • 时间切片 = 把大任务拆小 + 在浏览器空闲时执行
  • 它是 React 并发渲染的基础能力之一;
  • 依赖 Fiber 架构 + Scheduler 调度器 实现;
  • 开发者通过 startTransition / useDeferredValue 可主动优化性能;
  • 需使用 createRoot 启用并发模式才能生效。

三、优先级调度

React 的优先级调度(Priority-based Scheduling) 是 React 16 引入 Fiber 架构后的一项核心机制,用于优化 UI 渲染性能,确保高优先级任务(如用户交互)能够优先执行,而低优先级任务(如后台数据更新)可以被延迟或中断,从而提升用户体验。

React 将不同来源的更新赋予不同的优先级。以下是常见的优先级类型(从高到低):

优先级类型触发场景说明
Immediate(立即)ReactDOM.flushSync、错误边界恢复最高优先级,同步执行
User-blocking(用户阻塞)用户输入(如点击、按键)需要快速响应,避免卡顿
Normal(普通)setTimeoutPromise.then、网络请求回调默认优先级
Low(低)useDeferredValuestartTransition 中的更新可以稍后处理
Disable (Idle)(空闲)requestIdleCallback 类似行为只在浏览器空闲时执行

注意:React 18 后,这些优先级被进一步抽象为 Lane 模型(车道模型),用位运算高效管理多个并发更新的优先级组合。

总结:

  • React 优先级调度的核心目标:让 UI 响应更快、更流畅
  • 通过 Fiber + Lane 模型 + Scheduler 实现任务的中断、恢复、重排
  • 开发者可通过 startTransitionuseDeferredValue 等 API 主动控制更新优先级。
  • 这是 React 实现“并发模式(Concurrent Mode) ”的基础能力之一。

使用:

  • startTransition
  • useDeferredValue
  • suspense

注意:时间切片只对并发模式(Concurrent Mode)下的更新生效。如果你使用 ReactDOM.render(legacy 模式),则不会启用时间切片;需使用 createRoot

四、渲染 Render 过程

1. 整体流程概览

React 渲染分为两个主要阶段:

Render 阶段(可中断、异步)

  • 目标:构建新的 Fiber 树(WorkInProgress Tree)
  • 特点:可暂停、可恢复、可丢弃
  • 涉及机制:Fiber、时间切片、调度器、优先级调度

Commit 阶段(不可中断、同步)

  • 目标:将新 Fiber 树应用到 DOM
  • 特点:必须连续执行,不能被打断
  • 涉及机制:副作用(useEffect、ref 等)的执行、DOM 更新

关键思想:把“计算”和“提交”分离,让“计算”可以被中断,而“提交”保持原子性。

2.流程详解

步骤 1:触发更新(如 setState、useState)

setCount(c => c + 1);
  • React 将此次更新封装为一个 Update 对象
  • 根据触发源(用户点击、setTimeout、Transition 等),赋予不同 优先级(Lane)
  • 将更新加入 Fiber 节点的 updateQueue

步骤 2:调度器(Scheduler)介入

  • React 调用 Scheduler.unstable_scheduleCallback(priority, work)

  • 调度器根据优先级决定何时执行渲染任务:

    • 高优先级(如点击)→ 立即安排;
    • 低优先级(如 Transition)→ 等待浏览器空闲。

💡 调度器使用 MessageChannel 实现微任务队列,比 setTimeout(0) 更精准控制帧时机。

步骤 3:进入 Render 阶段(Fiber + 时间切片)

a) 初始化 WorkInProgress 树
  • React 创建或复用一棵 WorkInProgress Fiber 树(双缓冲机制);
  • 每个节点通过 fiber.alternate 指向 current 树的对应节点,实现内存复用。
b) 遍历组件树(BeginWork → CompleteWork)
  • 从根节点开始,深度优先遍历(DFS);

  • 对每个 Fiber 节点:

    • 调用函数组件或类组件的 render;
    • 协调(Reconcile)子节点,生成新的子 Fiber;
    • 标记副作用(如插入、更新、删除)。
c) 时间切片介入
  • 每处理几个 Fiber 节点,检查当前帧剩余时间(deadline);
  • 如果时间快用完(如 >5ms 已用),暂停工作,交还主线程给浏览器;
  • 下一帧继续从断点恢复(Fiber 天然支持暂停/恢复)。

✅ 这就是 时间切片:把大任务切成小块,在多个帧中完成。

d) 并发能力体现
  • 如果在 Render 阶段有更高优先级更新进来(如用户又点了按钮):

    • React 丢弃当前 WorkInProgress 树
    • 重新基于最新状态构建更高优的树;
    • 低优先级更新可能被“跳过”或“重做”。

这就是 并发渲染:多个更新可以“竞争”,高优胜出。

步骤 4:Render 阶段完成 → 进入 Commit 阶段

  • 当整棵 WorkInProgress 树构建完成且无错误;
  • React 原子性地root.current = workInProgress(双缓冲切换);
  • 开始 Commit 阶段(同步、不可中断)。

Commit 分三小步:

  1. Before Mutation

    • 执行 getSnapshotBeforeUpdate
    • 读取 DOM 状态(如滚动位置)。
  2. Mutation

    • 批量执行 DOM 操作(插入、更新、删除);
    • 这是实际修改 UI 的时刻。
  3. Layout

    • 执行 useLayoutEffectcomponentDidMount/Update
    • 可以同步读写 DOM(但要小心性能)。

⚠️ Commit 必须同步,因为涉及 DOM 操作,不能中途被打断。

步骤 5:Post-Commit(异步副作用)

  • 执行 useEffect(通过 Scheduler 异步调度);
  • 不阻塞浏览器绘制,避免卡顿。

3. 关键机制协同关系图

[ setState / useState ]
        ↓
[ 调度器 Scheduler ] ← 根据优先级安排任务
        ↓
[ Render 阶段 ]
   ├─ Fiber 架构:可中断的树遍历
   ├─ 双缓冲:current ↔ workInProgress
   ├─ 时间切片:分帧执行,不阻塞主线程
   └─ 并发:高优更新可打断低优
        ↓
[ Commit 阶段 ] ← 同步、原子性更新 DOM
        ↓
[ useEffect 异步执行 ]

4. 开发者如何配合?

场景推荐 API作用
用户输入响应默认行为高优先级,立即渲染
搜索过滤大量数据startTransition降级为低优先级,启用时间切片
延迟显示非关键内容useDeferredValue避免阻塞主 UI
启用并发能力createRoot必须使用新 Root API

5. 总结

React 的现代渲染是一个智能调度系统

  • Fiber 提供可中断的单元结构;
  • 双缓冲 保证更新安全与内存复用;
  • 调度器 + 优先级 决定“谁先干”;
  • 时间切片 决定“怎么干”(分帧);
  • 并发模式 允许“边干边换人”;
  • Commit 阶段 确保最终更新原子生效。

💡 最终目标:让高优先级交互始终流畅,低优先级工作默默完成