React 原理篇 - React 新架构深度解析

使用过 React v16 之前版本的开发者或许都经历过这样的场景:当页面包含复杂组件或大量列表时,输入框打字会卡顿,滚动会不流畅。这些体验问题的背后,往往与 React 的渲染机制密切相关。2017 年 React v16 推出的 Fiber 架构,正是为解决这些核心问题而生。本文将系统解读 React 新架构的演进之路。

一、旧架构的性能瓶颈:为什么会卡顿?

在 Fiber 出现之前,React 使用的是基于栈的递归协调(Stack Reconciler)机制。这种架构在处理复杂组件树时,会暴露出难以克服的性能问题。

1.1 不可中断的同步更新

JavaScript 是单线程语言,浏览器的渲染(UI 绘制)和脚本执行共用一个主线程。Stack Reconciler 采用深度优先递归方式比对虚拟 DOM,这种方式有一个致命缺陷:一旦开始执行,就必须等到整个组件树处理完成才能释放主线程。

想象一个包含 1000 个项目的列表:React 会从根组件开始,逐层递归处理每个子组件,整个过程无法暂停。如果这个过程耗时超过 16ms(浏览器每秒刷新 60 帧的时间间隔),就会阻塞渲染,导致页面卡顿。用户输入、鼠标移动等交互事件也会因为主线程被占用而无法及时响应。

1.2 缺乏优先级区分

旧架构对所有更新一视同仁,无法区分任务的轻重缓急。例如:

  • 用户正在输入搜索关键词(高优先级,需要即时反馈)
  • 同时页面在后台加载并渲染搜索结果(低优先级)

在 Stack 架构中,这两个任务会抢占主线程,可能导致输入框响应延迟,严重影响用户体验。

1.3 递归调用栈的限制

递归调用会形成一个连续的调用栈,栈的深度与组件树的深度一致。当组件树层级较深时,不仅容易导致栈溢出错误,更重要的是:JavaScript 引擎无法在递归过程中暂停执行某部分任务。这种机制使得 React 无法灵活应对运行时的各种情况,比如中途插入高优先级任务。

二、Fiber 架构:如何解决这些问题?

Fiber 架构的设计初衷,就是要打破 Stack Reconciler 的限制,实现 “可控的渲染过程”。它不是简单的优化,而是一次底层架构的重构。

2.1 核心目标:实现可中断、可恢复的更新

Fiber 架构通过两大革新实现这一目标:

  • 把渲染任务分解为小单元(每个单元对应一个组件的处理)
  • 每个单元执行完成后,允许暂停、恢复甚至放弃执行

这样,React 可以在处理完一个小单元后检查:是否有更高优先级的任务需要处理?当前是否已经超过了浏览器的一帧时间?如果是,就先释放主线程,等下一次机会再继续执行。

2.2 数据结构革新:从递归树到链表

Fiber 用链表结构替代了递归调用栈,每个 Fiber 节点就是一个工作单元。每个节点包含三个关键指针:

  • child:指向第一个子节点
  • sibling:指向兄弟节点
  • return:指向父节点

这种结构让 React 可以像 “遍历链表” 一样处理组件树,而不是依赖 JavaScript 引擎的调用栈。遍历过程可以随时暂停,因为当前进度可以通过这些指针被完整记录(比如 “当前处理到哪个节点,下一个该处理哪个节点”)。

// Fiber节点简化结构
const fiberNode = {type: 'div',        // 节点类型stateNode: domNode, // 对应的DOM节点child: null,        // 第一个子节点sibling: null,      // 兄弟节点return: null,       // 父节点// ...其他属性(优先级、更新队列等)
};

2.3 工作循环:分阶段处理任务

Fiber 架构将渲染过程分为两个阶段,实现了 “计算” 与 “执行” 的分离:

  1. 调度阶段(Reconciliation)
    • 负责找出前后虚拟 DOM 的差异(Diffing)
    • 为需要更新的节点打上标记(新增、删除、修改)
    • 可被中断:如果有更高优先级任务,可以暂停当前计算
  2. 提交阶段(Commit)
    • 根据调度阶段的标记,执行实际的 DOM 操作
    • 调用组件生命周期函数或 Hooks(如useEffect
    • 不可中断:确保 DOM 操作的原子性,避免页面出现不一致状态

这种分离设计,让 React 可以在调度阶段灵活调整执行顺序,同时保证最终 DOM 更新的稳定性。

三、调度器(Scheduler):让任务有轻重缓急

仅有 Fiber 结构还不够,还需要一个智能的调度系统来决定:什么时候该执行哪个任务?

3.1 优先级分级机制

React 调度器根据任务的紧急程度,将其分为不同优先级:

  • Immediate:同步执行,最高优先级(如用户输入)
  • UserBlocking:用户交互相关(如点击事件),需在 25ms 内完成
  • Normal:普通更新(如网络请求后的渲染),500ms 内完成
  • Low:低优先级任务(如列表预加载),1000ms 内完成
  • Idle:空闲时执行(如日志上报),没有时间限制

3.2 时间切片(Time Slicing)

调度器利用浏览器的requestIdleCallbacksetTimeout模拟时间切片,确保每个任务单元的执行不超过 5ms-10ms。每处理完一个单元,就检查是否超时或有更高优先级任务:

function workLoop() {// 只要有任务且未超时,就继续执行while (nextUnitOfWork && !shouldYield()) {nextUnitOfWork = performUnitOfWork(nextUnitOfWork);}
}// 判断是否需要让出主线程
function shouldYield() {return performance.now() >= deadline; // deadline是当前时间切片的截止时间
}

这种机制保证了主线程不会被长时间占用,浏览器有机会处理用户输入和渲染,从而避免卡顿。

四、双缓冲机制:提升渲染效率

Fiber 架构通过维护两棵树来优化渲染性能:

  • current 树:当前显示在页面上的 Fiber 树,与 DOM 节点一一对应
  • workInProgress 树:正在构建的新树,基于最新状态计算

当开始更新时,React 会以 current 树为基础,创建 workInProgress 树。对于不需要变更的节点,直接复用(通过alternate指针关联);需要更新的节点,创建新的 Fiber 节点。全部计算完成后,只需将根节点的指针从 current 树切换到 workInProgress 树,就能完成一次高效的更新。

这种 “双缓冲” 策略避免了频繁创建和销毁节点的开销,同时确保了 DOM 更新的原子性(用户不会看到中间状态)。

五、新架构带来的开发模式变革

Fiber 架构不仅解决了性能问题,更为 React 引入了新的开发能力,这些能力在 React 18 中得到了全面强化。

5.1 并发更新(Concurrent Updates)

在并发模式下,React 可以同时准备多个版本的 UI(比如快速输入时的多个中间状态),但只提交最终版本。这使得应用能在复杂计算的同时保持响应性。

import { startTransition } from 'react';// 输入框实时搜索示例
function Search() {const [input, setInput] = useState('');const [results, setResults] = useState([]);function handleChange(e) {setInput(e.target.value);// 标记搜索结果更新为低优先级startTransition(() => {setResults(searchApi(e.target.value));});}return (<div><input value={input} onChange={handleChange} /><ResultsList results={results} /></div>);
}

startTransition告诉 React:输入框更新(setInput)是紧急的,而搜索结果更新(setResults)可以延迟,不会阻塞用户输入。

5.2 性能优化的最佳实践

基于新架构的特性,我们可以采用更精准的优化策略:

  • 拆分组件:将大组件拆分为小组件,让任务单元更细,便于中断和恢复
  • 使用React.memo:减少不必要的重渲染,尤其适合列表项组件
  • 合理使用优先级 API:通过startTransitionuseDeferredValue区分紧急与非紧急更新
  • 虚拟滚动:对于超长列表,只渲染可视区域内的项

六、总结

Fiber 架构的意义远不止于性能提升,它代表了 React 设计理念的转变:

  • 以用户体验为中心:优先保证交互响应速度,而非追求代码执行效率
  • 增量计算思想:将复杂任务分解为可增量处理的单元,适应浏览器的工作机制
  • 弹性设计:通过优先级和中断机制,让应用能灵活应对不同运行时环境

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/96916.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/96916.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JavaSE五天速通|第三篇】常用API与日期类篇

适合有其他语言基础想快速入门JavaSE的。用的资料是 Java入门基础视频教程 &#xff0c;从中摘取了笔者认为与其他语言不同或需要重点学习的内容 常用API与日期类只需要有印象即可&#xff0c;用到了再来这查 day04 常用API 一、StringBuilder类 StringBuilder代表可变字符…

K8s学习笔记(二) Pod入门与实战

1 K8s核心资源Pod 1.1 Pod是什么&#xff1f; 官方文档&#xff1a;Pod | Kubernetes Pod 是 Kubernetes&#xff08;k8s&#xff09;中最小的部署与调度单元&#xff0c;并非直接运行容器&#xff0c;而是对一个或多个 “紧密关联” 容器的封装。 核心特点可简单总结为 3 …

用 Python 调用 Bright Data MCP Server:在 VS Code 中实现实时网页数据抓取

用 Python 调用 Bright Data MCP Server&#xff1a;在 VS Code 中实现实时网页数据抓取&#xff0c;本文介绍了Bright Data的Web MCP Server&#xff0c;这是一款能实现实时、结构化网页数据访问的API&#xff0c;适用于AI应用等场景。其支持静态与动态网页&#xff0c;前3个月…

SPSS绘制ROC曲线并计算灵敏度、特异度

SPSS绘制ROC曲线并计算灵敏度、特异度。 &#xff08;1&#xff09;绘制ROC曲线&#xff1a; 输入&#xff1a;预测值、受试者标签。 在SPSS中点击“分析”-“分类”-“ROC曲线” 变量输入&#xff1a;检验变量输入预测值&#xff0c;状态变量输入受试者标签&#xff0c;如果标…

Modbus协议原理与Go语言实现详解

目录 Modbus协议概述协议架构与通信模式Modbus数据模型Modbus协议帧格式功能码详解Go Modbus库完整实现高级应用示例调试与故障排除 Modbus协议概述 Modbus是一种串行通信协议&#xff0c;由Modicon公司&#xff08;现施耐德电气&#xff09;于1979年开发&#xff0c;用于PL…

下载CentOS 7——从阿里云上下载不同版本的 CentOS 7

没有废话&#xff0c;直接上干货。跟着图片教程&#xff0c;一步一步来就行。 想下载其它版本的&#xff0c;自己可以再选择其它的就行。 想省事的朋友可以直接点击: 1、下载页面链接 2、CentOS-7-x86_64-DVD-2207-02(4.4GB).iso

SpringBoot -原理篇

文章目录配置优先级Bean管理获取beanbean作用域第三方beanSpringBoot原理起步依赖自动配置自动配置原理方案源码跟踪原理分析 Conditional案例&#xff08;自定义starter&#xff09;案例&#xff08;自定义starter分析&#xff09;案例&#xff08;自定义starter实现&#xff…

JavaScript与jQuery:从入门到面试的完整指南

JavaScript与jQuery&#xff1a;从入门到面试的完整指南 第一部分&#xff1a;JavaScript基础 1.1 JavaScript简介 JavaScript是一种轻量级的解释型编程语言&#xff0c;主要用于Web开发&#xff0c;可以为网页添加交互功能。它是ECMAScript规范的一种实现。 // 第一个JavaScri…

解决:Ubuntu、Kylin、Rocky系统中root用户忘记密码

解决Linux系统中root用户忘记密码 Ubuntu2204 重启电脑&#xff0c;启动时&#xff0c;长按Shift键&#xff08;对于 BIOS 系统&#xff09;或 Esc 键&#xff08;对于 UEFI 系统&#xff09;进入GRUB菜单 步骤1&#xff1a;重启Ubuntu系统&#xff0c;长按Shift键进入Ubuntu…

ENVI系列教程(二)——自定义坐标系(北京 54、西安 80、2000 坐标系)

目录 1 概述 1.1 地理投影的基本原理 1.2 国内坐标系介绍 1.3 参数的获取 2 详细操作步骤 2.1 添加椭球体 2.2 添加基准面 2.3 定义坐标系 2.4 使用自定义坐标系 1 概述 1.1 地理投影的基本原理 常用到的地图坐标系有 2 种,即地理坐标系和投影坐标系。地理坐标系是…

一种基于因果干预的少样本学习的故障诊断模型

一、研究背景与问题 ​工业背景​:机械故障诊断对工业系统安全至关重要,但实际中故障样本稀少,难以训练传统深度学习模型。 ​现有问题​: 当前少样本学习(FSL)方法大多基于相关性而非因果关系建模,容易学习到伪相关特征,导致模型可解释性差、泛化能力弱。 跨组件故障诊…

机器视觉光源的尺寸该如何选型的方法

机器视觉光源的尺寸该如何选型的方法&#x1f3af;机器视觉光源的尺寸选型的方法&#x1f3af;一、选型案例&#x1f3af;二、照射方式&#x1f3af;三、镜头选择&#x1f3af;四、光源架构光源的工作距离与视野大小&#x1f3af;五、总结&#xff1a;光源选型 —— 机器视觉检…

HTML新属性

HTML5引入了许多新属性&#xff0c;旨在增强语义化、交互性和多媒体支持。以下是一些重要的新属性及其用途分类&#xff1a;语义化与结构属性data-*&#xff1a;自定义数据属性&#xff0c;允许开发者存储额外信息&#xff08;如data-id"123"&#xff09;。hidden&am…

从工地到链上:一个土建人的 Web3 转行经历

Web3 的风&#xff0c;终究还是吹到了土建行业。2017 年&#xff0c;土建专业&#xff08;给排水工程&#xff09;的刘正源偶然看到一则关于比特币的新闻&#xff0c;被它背后的经济模型与技术架构深深震撼。到了 2021 年&#xff0c;他在工地上再次听人提起区块链&#xff0c;…

20250914-03: Langchain概念:提示模板+少样本提示

20250914-03: Langchain概念&#xff1a;提示模板少样本提示 聊天模型 消息 提示 结构化输出 &#x1f3af; 学习目标 掌握如何“喂给模型正确的输入”并“解析出想要的输出”。 &#x1f517; 核心概念 ​聊天模型&#xff08;ChatModel&#xff09;​消息&#xff08;M…

【AI推理部署】Docker篇04—Docker自动构建镜像

Docker 自动构建镜像1. Dockfile 编写2. 镜像使用使用 Dockerfile 构建镜像 Dockerfile 其实就是把我们前面的一系列安装、配置命令写到一个文件中&#xff0c;通过 docker build 命令&#xff0c;一键完成镜像的构建。接下来&#xff0c;我们以 bitnami/pytorch:2.1.1 作为基础…

LeetCode 674.最长连续递增序列

给定一个未经排序的整数数组&#xff0c;找到最长且 连续递增的子序列&#xff0c;并返回该序列的长度。 连续递增的子序列 可以由两个下标 l 和 r&#xff08;l < r&#xff09;确定&#xff0c;如果对于每个 l < i < r&#xff0c;都有 nums[i] < nums[i 1] &am…

贪心算法java

贪心算法简介贪心算法是一种在每一步选择中都采取在当前状态下最优&#xff08;局部最优&#xff09;的选择&#xff0c;从而希望导致结果是全局最优的算法。贪心算法通常用于解决最优化问题&#xff0c;如最短路径、最小生成树、任务调度等。贪心算法的基本步骤问题分析&#…

【华为OD】解锁犯罪时间

【华为OD】解锁犯罪时间 题目描述 警察在侦破一个案件时&#xff0c;得到了线人给出的可能犯罪时间&#xff0c;形如"HH:MM"表示的时刻。根据警察和线人的约定&#xff0c;为了隐蔽&#xff0c;该时间是修改过的&#xff0c;解密规则为&#xff1a;利用当前出现过的数…

基于linux操作系统的mysql安装

一、检查自己的操作系统是否已经有存在的mysql 1.存在 2.不存在 二、基于操作系统不存在mysql,找官方yum源 网址&#xff1a; Index of /232905https://repo.mysql.com/ 网站打开是这样 看看自己的操作系统是哪个版本&#xff0c;再下载哪个版本&#xff0c;如果和我一样装…