创见博客
React18的并发特性
七崽爱吃小饼干2026/01/09阅读 0专栏 React

React 18 并发特性(Concurrent Mode)

一、官方标准定义:React 两大核心阶段

阶段一:「渲染阶段(Reconciliation / 调和阶段)」

也被 React 源码称为 workInProgress(工作中)阶段,这是 React 做「内存计算」的核心阶段。

核心特征

  1. 纯内存计算,不碰真实DOM:这个阶段只做「虚拟DOM对比(Diff)、构建/更新 Fiber 树、标记DOM的增/删/改操作」,所有操作都在内存中完成,浏览器页面完全没有任何变化,用户完全感知不到这个阶段的存在;
  2. 无副作用执行:不会执行 useEffect、类组件的 componentDidMount/Update 生命周期,不会更新 Ref 引用,不会触发任何业务侧的副作用逻辑;
  3. React18 核心变更点:React16/17 中这个阶段是「同步不可中断」的,React18 中这个阶段是「可中断、可恢复、可取消」的(并发特性的唯一作用区域);
  4. 可丢弃,无任何风险:就算渲染阶段执行到一半被中断/丢弃,也不会有任何页面BUG、内存泄漏,因为没有修改任何真实的浏览器资源,就像「草稿纸上的演算过程被擦掉」一样。

这个阶段到底做了什么?

基于最新的状态,算出「页面需要怎么更新」,并生成一份「DOM更新操作清单」,仅此而已。


阶段二:「提交阶段(Commit)」

这是 React 做「真实浏览器操作」的唯一阶段,也是页面真正发生变化的阶段,React 源码中也叫「完成阶段」。

核心特征

  1. 操作真实DOM,触发展现变化:唯一会执行「渲染阶段生成的DOM操作清单」的阶段,调用原生 DOM API(appendChild/removeChild/setAttribute)完成真实DOM的增删改,执行完这一步,用户才能看到页面的变化;
  2. 同步执行、不可中断、原子化完成:一旦提交阶段开始,就必须「一口气执行到底」,JS主线程会被完全占用,任何任务都无法插队、无法中断,哪怕是用户的点击/输入交互也会被暂存。
    • 为什么必须不可中断?这是 React 的「保命设计」:DOM是浏览器的共享全局资源,如果DOM更新到一半被中断,会出现页面UI撕裂、DOM节点残缺、状态和视图不一致的致命BUG,这种错误是前端无法修复的,所以「原子化更新」是底线;
  3. 执行所有副作用逻辑:提交阶段是 React 执行「副作用」的唯一时机,包含:
    • 函数组件:执行 useEffect / useLayoutEffect 钩子;
    • 类组件:执行 componentDidMount / componentDidUpdate / componentWillUnmount 生命周期;
    • 所有组件:更新 useRef / createRef 的引用指向,让你能拿到真实DOM节点。
  4. 耗时极短,几乎无感知阻塞:提交阶段做的都是「执行指令」而非「做计算」,DOM操作是浏览器底层C++实现的,哪怕更新几百个DOM节点,耗时也在 0.1~2ms 之间,远小于浏览器16.67ms的帧刷新间隔,所以我们几乎感知不到交互阻塞。

这个阶段到底做了什么?(一句话说透)

把渲染阶段算出的「DOM更新清单」落地成真实页面变化,并执行所有需要在DOM更新后触发的业务逻辑。


二、先明确核心:React18 的「并发」到底是什么?

2.1 官方定义

React18 的并发特性(Concurrent Rendering) 是一种可中断、可暂停、可恢复、可取消的渲染机制。它允许 React 在渲染一个耗时任务的过程中,临时中断当前渲染,优先去处理优先级更高的任务(比如用户点击/输入/滚动),等高优先级任务执行完毕后,再恢复之前被中断的渲染;如果后续又出现更高优任务,甚至可以直接丢弃之前未完成的渲染任务,避免无效计算。

2.2 核心对比:React18 之前的「同步渲染」

React18 发布前,所有版本的渲染都是同步且不可中断的同步渲染,这个特性是 React 一直以来的性能痛点:

  • 工作机制:一旦 React 开始渲染(从 render 到 commit 阶段),就会「一口气执行到底」,在渲染完成前,JavaScript 主线程会被完全占用。
  • 致命问题:JS 是单线程语言,主线程被占用时,浏览器的布局(Layout)、绘制(Paint)、用户事件响应都会被阻塞。
    • 现象:如果组件层级深、数据量大(比如长列表渲染),页面会出现卡顿、掉帧、用户操作无响应(比如点击按钮没反应、输入框打字延迟),体验极差。
    • 本质:同步渲染中「渲染任务」和「用户交互任务」是串行排队的,没有优先级之分。

2.3 一句话总结核心区别

  • 同步渲染:渲染一旦开始,必须执行完,阻塞一切,优先级无差别;
  • 并发渲染:渲染可以被打断,优先级高的任务插队优先执行,不阻塞用户交互,是「协作式」的渲染机制。

三、为什么 React18 要推出「并发特性」?核心设计目标

React 团队做这个重大重构,核心只有一个目标:在不牺牲代码可读性/开发体验的前提下,解决「渲染阻塞导致的用户体验问题」,让 React 应用的交互更流畅、响应更及时。

补充一个重要细节:

React18 的并发特性不是「多线程渲染」,React 依然运行在浏览器的 JS 主线程中,没有开启新线程!并发的实现是「逻辑层面的调度」,而非「操作系统层面的多线程」,这点一定要记牢,避免理解偏差。


四、并发渲染的 3 个核心关键特性

React 18 的并发能力,核心体现在 3 个不可分割的特性上,这也是理解并发的基石,可中断、可恢复、可取消 三者相辅相成:

特性1:可中断 (Interruptible)

React 在「渲染阶段(Reconciliation)」执行 diff 算法、生成 Fiber 树的过程中,不再是一次性执行,而是会把渲染任务拆分成多个小的执行单元。

  • 浏览器有一个「空闲调度机制」,React 会在浏览器的每一帧空闲时间执行一个小单元的渲染任务;
  • 一旦浏览器需要执行高优先级任务(用户点击、输入、动画),React 会立刻「中断」当前的渲染小单元,把主线程让出去;
  • 核心范围:只有「渲染阶段」可以被中断,「提交阶段(Commit)」(真实DOM更新、执行useEffect/componentDidMount等)依然是同步不可中断的!因为DOM操作必须原子化,否则会出现页面UI撕裂、状态不一致的问题。

特性2:可恢复 (Resumable)

这是「可中断」的配套能力:当被中断的渲染任务对应的高优先级任务执行完毕后,浏览器主线程再次空闲时,React 不需要「从头开始重新渲染」,而是可以从之前中断的那个执行单元继续往下渲染。

  • 实现原理:React18 的 Fiber 架构本身就是「链表结构」,每个 Fiber 节点都记录了当前的渲染进度,这是可恢复的技术基础;
  • 核心价值:极大减少无效计算,提升渲染效率,这也是并发渲染比「分片渲染」更优秀的地方。

特性3:可取消 (Cancelable)

这是并发渲染的「灵魂特性」,也是最能体现性能优势的一点,优先级最高的特性:

  • 工作机制:如果 React 正在渲染一个低优先级任务(比如列表懒加载、非可视区域的组件渲染),此时触发了一个高优先级任务(比如用户点击按钮、输入框打字、下拉刷新),React 会直接丢弃这个未完成的低优先级渲染任务,不再继续执行,而是立即执行高优先级任务;
  • 关键补充:被取消的渲染任务不会留下任何副作用(比如不会更新DOM、不会执行副作用钩子),因为副作用只在「提交阶段」执行,而渲染阶段的计算都是内存中的临时操作;
  • 极致体验:用户的交互操作永远不会被「后台的渲染任务」阻塞,用户操作的响应优先级永远是最高的,这彻底解决了 React 应用「点击没反应、打字卡顿」的核心痛点。

五、并发渲染的核心支撑:优先级调度机制

所有的「可中断/可恢复/可取消」,本质上都是基于 React18 内置的 优先级调度系统 实现的,这是并发特性的「底层引擎」,没有优先级调度,并发就是空中楼阁。

5.1 核心原则

React 会为每一个更新任务(setState、useState修改)分配一个优先级,调度器会始终遵循:高优先级任务优先执行,低优先级任务让步于高优先级任务。

5.2 常见任务优先级排序(从高到低,熟记)

React 内置了一套优先级规则,日常开发中能感知到的优先级排序如下:

  1. 用户交互类(最高):用户输入(input/textarea打字)、鼠标点击、滚动、拖拽、触摸事件 → 这类任务必须立即响应,延迟超过16ms用户就会感知到卡顿;
  2. 动画过渡类:CSS动画、React过渡动画(比如react-transition-group)、弹窗显隐 → 要求60fps流畅,优先级仅次于用户交互;
  3. 数据更新类:接口请求成功后的列表数据渲染、表单提交后的反馈渲染 → 优先级中等;
  4. 后台计算类(最低):懒加载组件、非可视区域的渲染、大数据量的统计计算、防抖后的搜索联想(延迟执行的)→ 这类任务可以被无限中断/取消。

5.3 调度的核心实现:基于浏览器的 requestIdleCallback + 自研调度器

React 没有直接依赖浏览器原生的 requestIdleCallback(因为兼容性和触发频率问题),而是自研了一套更精准的调度器(Scheduler 包),核心逻辑是:

  • 利用 requestAnimationFrame 监听浏览器的每一帧;
  • 在每一帧的「空闲时间」执行低优先级的渲染任务;
  • 一旦检测到有高优先级任务进入队列,立刻中断当前任务,切换执行高优先级任务。

六、React18 如何开启并发特性?

6.1 关键前提:并发特性是「渐进式启用」的,无破坏性更新

React 团队的核心设计理念:完全向后兼容,升级 React18 后,你的旧项目代码不需要任何修改就能正常运行,因为 React18 的并发特性是「选择启用」的,不是默认开启的。

6.2 开启并发模式的唯一入口:createRoot

React18 发布了两个根节点创建API,这是区分「是否开启并发特性」的唯一标准:

✔️ 旧版 API(同步渲染,默认):ReactDOM.render

jsx
import ReactDOM from 'react-dom';
import App from './App';

// React18之前的写法,React18中保留,但运行在「同步渲染模式」
// ❌ 不会启用任何并发特性
ReactDOM.render(<App />, document.getElementById('root'));

✔️ 新版 API(并发渲染,手动开启):ReactDOM.createRoot

jsx
import ReactDOM from 'react-dom/client'; // 注意导入路径变化
import App from './App';

// React18的新写法,✅ 完全启用所有并发特性
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

✅ 核心结论:只有使用 createRoot 创建根节点,你的 React 应用才会运行在「并发模式」下,拥有所有并发特性;使用旧的 ReactDOM.render 则还是原来的同步渲染模式,这也是 React18 「无痛升级」的核心保障。


七、总结:React18 并发特性的核心价值(精华提炼)

  1. React18 的并发渲染(Concurrent Rendering) 是「可中断、可恢复、可取消」的渲染机制,核心解决「同步渲染阻塞用户交互」的痛点;
  2. 并发不是多线程,是「逻辑层面的优先级调度」,渲染阶段可中断,提交阶段不可中断;
  3. 并发特性默认不开启,唯一开启方式是使用 ReactDOM.createRoot 替代旧的 ReactDOM.render;
  4. 核心配套能力是 useTransition、useDeferredValue、稳定版 Suspense,这三个是开发中最常用的并发API;
  5. 并发特性是 React 从「同步渲染」到「异步调度渲染」的里程碑式重构,也是 React 未来所有新特性的基础;
  6. 核心体验提升:用户交互永远优先,应用再也不会因为渲染而卡顿,这是 React18 最核心的价值。
评论
0/100