React进阶之React核心源码解析(一)
React核心源码解析
- react 特点
- CPU卡顿
- IO 卡顿
- 新老 react 架构对比
- v15
- v16.8
- Scheduler 调度器
- Reconciler 协调器
- React fiber
- 原理
- 更新dom
- mount 构建过程
- render阶段 — scheduler reconciler
- react源码解析
- react-dom
- react-dom/src/client/ReactDOMRoot.js
- react-reconciler
- react-reconciler/src/ReactFiberReconciler.js
- react-reconciler/src/ReactFiberWorkLoop.js
- react-reconciler/src/ReactFiberBeginWork.js
- react-reconciler/src/ReactChildFiber.js
- react-reconciler/src/ReactFiber.js
- react-reconciler/src/ReactFiberWorkLoop.js
- commit阶段 同步阶段
cline + deeseek => AI工具,上手成本非常低,非常便宜
cursor 编辑器
带着问题学源码
- 为什么 react 会引入 fiber 架构
- 简述 fiber 节点的结构和作用
- fiber 架构 => 架构+流程
- diff 算法
- hooks 原理
学习方法论:由大到小 对比回答问题
react 特点
- 单向数据流
能够快速响应用户操作
公式:ui = render(data)
什么原因导致响应慢?
cpu卡顿,js执行导致画面卡顿
IO卡顿,网络问题等 延迟
CPU卡顿
浏览器一秒60hz,16.6ms刷新一次,超过就会有掉帧现象
就比如这个例子
// index.js
import ReactDOM from "react-dom";import App from "./App";const rootElement = document.getElementById("root");// ReactDOM.render(<App />, rootElement);
ReactDOM.createRoot(rootElement).render(<App />);// APP.js
import "./styles.css";export default function App() {const len = 3000;return (<ul>{Array(len).fill(0).map((_, i) => (<li>{i}</li>))}</ul>);
}
React是怎么解决的?
时间分片:把更新过程碎片化 优先级 应用更新 后台预渲染
- 同步 阻塞 渲染
- 异步 非阻塞 用户优先级渲染
16.8后提出的 concurrent mode
ReactDOM.createRoot(rootEl).render(<App />)
IO 卡顿
接口响应时间长,解决:
- loading
- suspence 兜底 fallback
- error-boundary 错误兜底

新老 react 架构对比
v15 同步的,不可中断的
v16.8 异步,可中断
v18 ssr升级 流式 ssr stream,针对页面所有组件是分块,分局部输出,而不是等所有页面拼接组装好后一次性传输给客户端
页面上的不同接口,包裹成流式,然后传输给客户端,提升TTFB(首字节响应时间)
性能优化有需求,使用nextjs做提升
v15
- Reconciler 协调器,diff 负责找出变化的组件
- update 更新
- component render jsx 渲染 => vdom
- vdom diff
- 找出变化的元素
- 通知 renderer 渲染
通过递归的方式找出变化的组件
mount 阶段 => 调用 mountComponent
update 阶段 => 调用 updateComponent
递归更新子组件
=> 缺点:层级深,递归时间超过16ms
- Renderer 渲染器,负责将变化的组件渲染到页面上
- ReactDom.render
- ReactNative.render
不可中断,中断则后续内容不执行
v16.8
多了一个 Scheduler 调度器
- Scheduler 调度器 调度任务的优先级
- Reconciler 协调器 负责找出变化的组件 递归=>可中断
- Renderer 渲染器 是拿着Reconciler提供的标识 同步渲染
Scheduler 调度器
将大型任务分割成小任务,每一帧分配一定的时间执行小任务
- 时间切片
- 优先级调度
- 每个工作单元,对应一个fiber节点
- 时间分配
- 调度循环 维护任务队列
- 时间检查
- 暂停与恢复
- 利用浏览器API
- requestAnimationFrame 用于在下一帧开始的时候执行回调函数
- requestIdleCallBack 浏览器空闲的时候执行回调函数 setTimeout 模拟了
Reconciler 协调器
// 更新工作从递归变成了可以中断的循环过程。每次循环都会调用shouldYield判断当前是否有剩余时间。/** @noinline */
function workLoopConcurrent() {// Perform work until Scheduler asks us to yieldwhile (workInProgress !== null && !shouldYield()) {workInProgress = performUnitOfWork(workInProgress);}
}
React fiber
原理
react 内部实现的数据结构,支持状态更新,可中断可恢复,恢复后可以复用之前的中间状态
- 架构:v15 stack reconciler,v16 fiber reconciler
- 数据结构:每个 fiber 节点对应 react element,多个组件类型,dom节点各种属性数据
- 动态的工作单元,改变的状态,要执行的工作
function FiberNode(tag: WorkTag,pendingProps: mixed,key: null | string,mode: TypeOfMode,
) {// Instance,静态节点的数据结构属性this.tag = tag;this.key = key;this.elementType = null;this.type = null;this.stateNode = null;// Fiber,用来链接其他fiber节点形成的fiber树this.return = null;this.child = null;this.sibling = null;this.index = 0;this.ref = null;// 作为动态的工作单元的属性this.pendingProps = pendingProps; //即将应用到组件上新属性 相当于是新值newValue this.memoizedProps = null; // 上次渲染时使用的属性值 相当于是旧值oldValuethis.updateQueue = null;this.memoizedState = null;this.dependencies = null;this.mode = mode;// 记录变化的节点 effectlist=>renderthis.effectTag = NoEffect;this.subtreeTag = NoSubtreeEffect;this.deletions = null;this.nextEffect = null;// effectslist链 = firstEffect -> nextEffect -> nextEffect -> lastEffect => 交给render => 渲染this.firstEffect = null;this.lastEffect = null;// 作为调度优先级的属性this.lanes = NoLanes;this.childLanes = NoLanes;// 指向该fiber在另一次更新时对应的fiberthis.alternate = null;if (enableProfilerTimer) {// Note: The following is done to avoid a v8 performance cliff.//// Initializing the fields below to smis and later updating them with// double values will cause Fibers to end up having separate shapes.// This behavior/bug has something to do with Object.preventExtension().// Fortunately this only impacts DEV builds.// Unfortunately it makes React unusably slow for some applications.// To work around this, initialize the fields below with doubles.//// Learn more about this here:// https://github.com/facebook/react/issues/14365// https://bugs.chromium.org/p/v8/issues/detail?id=8538this.actualDuration = Number.NaN;this.actualStartTime = Number.NaN;this.selfBaseDuration = Number.NaN;this.treeBaseDuration = Number.NaN;// It's okay to replace the initial doubles with smis after initialization.// This won't trigger the performance cliff mentioned above,// and it simplifies other profiler code (including DevTools).this.actualDuration = 0;this.actualStartTime = -1;this.selfBaseDuration = 0;this.treeBaseDuration = 0;}if (__DEV__) {// This isn't directly used but is handy for debugging internals:this._debugID = debugCounter++;this._debugSource = null;this._debugOwner = null;this._debugNeedsRemount = false;this._debugHookTypes = null;if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {Object.preventExtensions(this);}}
}

举个例子:
import React, { Component } from 'react';class Header extends Component {render() {return <h1>{this.props.title}</h1>;}
}function Content(props) {return (<div><p>{props.text}</p><Footer /></div>);
}class Footer extends Component {render() {return <footer>Footer Content</footer>;}
}class App extends Component {render() {return (<div><Header title="Welcome to My App" /><Content text="This is some example content." /></div>);}
}export default App;
Fiber结构:
Root Fiber Node
└── Type: “div” (elementType: “div”)
├── Child Fiber Node
│ ├── Type: “Header” (elementType: Header)
│ │ └── State Node: Header instance
│ │ └── Props: { title: “Welcome to My App” }
│ └── Sibling: Content Fiber Node
└── Child Fiber Node
├── Type: “Content” (elementType: Content)
│ └── State Node: null (函数组件没有状态节点)
│ └── Props: { text: “This is some example content.” }
│ └── Child Fiber Node
│ ├── Type: “Footer” (elementType: Footer)
│ │ └── State Node: Footer instance
│ │ └── Props: {}
│ └── Sibling: null
更新dom
双缓存机制
内存中绘制当前的 fiber dom,绘制完后直接替换上一帧的fiber dom,这样省去两帧之间替换的计算时间,就不会存在白屏的情况,因此就有两棵fiber树
- current fiber 屏幕上正在显示的内容
- workingprogress fiber 内存中正在构建的树 简称 wip fiber
alternate 连接


mount 构建过程
- 应用级别的节点 ReactDom.render 创建 fiberRootNode
- rootFiber 组件树的根节点

render阶段 — scheduler reconciler
通过遍历 找到所有的fiber结构 实现可中断的异步递归
- 递 => 生成树
创建节点,形成节点之间的关系
vdom
从 rootfiber 深度优先遍历 fiber 调用 beginwork
- 根据传入的 fiber 节点创建子 fiber 节点,连接两个 fiber 节点
- 遍历叶子节点,进入归的阶段
- 归
调用completework
- 创建真实的dom节点
- 将当前节点下的子节点挂载到当前节点上
- 收集当前节点的effectlist
递 归 交错执行,直到归到rootFiber

react源码解析
react github
react-dom

react-dom/src/client/ReactDOMRoot.js


最终返回ReactDOMRoot这个实例
ReactDOMRoot 和 ReactDOMHydrationRoot 上面都挂载 render 方法
接收children
调用updateContainer方法,传入children,updateContainer来进行递归的这个阶段,创建当前节点

后面还挂载了unmount方法

react-reconciler
react-reconciler/src/ReactFiberReconciler.js
这里着重是 Scheduler
创建FiberRootNode节点绑定root
render渲染方法传入children(App),调用updateContainer方法,进行大任务拆分小任务,优先级调度

react-reconciler/src/ReactFiberWorkLoop.js
着重介绍循环创建fiber树的方法
核心方法:performUnitOfWork,workLoopConcurrent
workLoopSync 同步方法,不会判断 shouldYield,这是和workLoopConcurrent方法的区别

workLoopConcurrent方法是异步模式,都是调用performUnitOfWork构造fiber树

这里是Scheduler调度器将渲染任务拆分成不同的任务单元去创建对应的fiber,fiber通过performUnitOfWork去完成fiber单元的创建,然后通过shouldYield判断是否执行这样的任务
workInProgress是全局的变量,存储在全局
performUnitOfWork中记录当前“递”和“归”的一个过程,判断当前满足条件,进入beginWork
Reconciler 协调器阶段,创建fiber树,递归遍历,diff算法比较差异
performUnitOfWork中判断是否是开发环境,开发环境开启性能调优则计算执行时间
调用beginWork进行节点的递阶段,拆解组件内容,并且返回下一个组件
当深度遍历到最底层的时候,开始进行归的阶段
则next为空,调用completeUnitOfWork开始”归“的阶段,归回父节点,更新父节点状态
"递"和"归"阶段是交错执行的,直到回到rootFiber为止

react-reconciler/src/ReactFiberBeginWork.js
- beginWork

if 阶段:后续进入到diff的过程,非首次渲染
否则为else阶段
后面:

-
updateHostComponent

-
reconcileChildren
mount组件:创建新的子Fiber节点

react-reconciler/src/ReactChildFiber.js


、

通过调用useFiber创建fiber节点

react-reconciler/src/ReactFiber.js
找到workInProgress,为null则创建Fiber节点



不论是哪个方法,最终返回的都是 workInProgress.child下一个节点
react-reconciler/src/ReactFiberWorkLoop.js
performUnitOfWork中
上述 beginWork返回的是workInProgress.child下一个节点,因此next就会发生变化
next为null时候,则叶子节点为空,调用completeUnitOfWork

next不为空,则将next指针赋值给workInProgress,修改workInProgress指向,重新执行beginWork
在 completeUnitOfWork 中,创建对应的dom元素,如果sibling不为null,然后创建对应的指针

commit阶段 同步阶段
effectlist
- before mutation 阶段,执行 dom操作前
- mutation 阶段,执行dom操作阶段,遍历effectlist,执行mutation
- layout 阶段,执行dom操作后,绘制
可以自己写一个实例,然后打断点看操作数据,操作结果

一句话来总结commit阶段所作的事情:
基于链表的方式存储副作用,并根据优先级执行这些更新,直至所有的更新完成。
- React遍历fiber树并将需要执行副作用的节点以链表的形式收集起来
- 根据优先级存储更新
- 递归执行更新
相关文章:
React进阶之React核心源码解析(一)
React核心源码解析 react 特点CPU卡顿IO 卡顿 新老 react 架构对比v15v16.8Scheduler 调度器Reconciler 协调器 React fiber原理更新dommount 构建过程 render阶段 — scheduler reconcilerreact源码解析react-domreact-dom/src/client/ReactDOMRoot.js react-reconcilerreact-…...
用大模型学大模型03-数学基础 概率论 条件概率 全概率公式 贝叶斯定理
要深入浅出地理解条件概率与贝叶斯定理,可以从以下几个方面入手,结合理论知识和实例进行学习: 贝叶斯定理与智能世界的暗语 条件概率,全概率公式与贝叶斯公式的推导,理解和应用 拉普拉斯平滑 贝叶斯解决垃圾邮件分类 …...
C++ Primer 参数传递
欢迎阅读我的 【CPrimer】专栏 专栏简介:本专栏主要面向C初学者,解释C的一些基本概念和基础语言特性,涉及C标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级…...
Jupyter lab 无法导出格式 Save and Export Notebook As无法展开
本来尝试jypyter lab如何导出HTML带有侧边导航栏,一顿操作后发现还是没实现。 又突然发现导出其他格式地功能不能用了,浏览器里Save and Export Notebook As展开按钮为灰色打不开。 经典想实现的没实现还把原先的搞坏了。 看了jupyter lab的运行信息发…...
Mac之JDK安装
Mac之JDK安装 一.安装 jdk 打开终端输入命令:java -version 查看是否已安装 JDK Oracle 官方下载地址 根据自己Mac 系统安装 查看 Mac 系统,打开中断命令,输入: uname -a Compressed Archive 是压缩文档,下载的是一个 .tar.gz 压缩包 D…...
OpenEuler学习笔记(三十一):在OpenEuler上搭建仓颉语言开发环境
仓颉语言(Cangjie programming language)相对较为小众,截至2025年,并没有广泛的资料和成熟的通用搭建流程。不过下面为你提供一个较为通用的在OpenEuler上搭建开发环境的大致思路,你可以根据实际情况进行调整。 1. 安…...
2021年全国研究生数学建模竞赛华为杯E题信号干扰下的超宽带(UWB)精确定位问题求解全过程文档及程序
2021年全国研究生数学建模竞赛华为杯 E题 信号干扰下的超宽带(UWB)精确定位问题 原题再现: 一、背景 UWB(Ultra-Wideband)技术也被称之为“超宽带”,又称之为脉冲无线电技术。这是一种无需任何载波,通过发送纳秒…...
【电脑】u盘重装win7
u盘必须8GB以上 1. CPU型号 首先查看CPU的型号看看到底能不能装win7 2. 下载光盘映像文件 网址 看电脑是多少位的机器(32位下载x86 64位下载x64) 一共是这么多个版本按需下载对应的版本 电脑小白推荐无脑下载旗舰版 将链接复制到迅雷进行下载 3. 下载软碟通 网址 下…...
HCIA项目实践--RIP的拓展配置
9.4.7 RIP的拓展配置 (1)RIPV2的手工认证 RIPv2 的手工认证是增强网络安全性的手段。管理员手动配置密钥,路由器在收发 RIPv2 路由更新消息时,会对消息中的认证信息进行检查。发送方添加密钥,接收方用预设密钥验证。若…...
常用架构图:业务架构、产品架构、系统架构、数据架构、技术架构、应用架构、功能架构及信息架构
文章目录 引言常见的架构图I 业务架构图-案例模块功能说明1. 用户界面层 (UI)2. 应用服务层3. 数据管理层4. 基础设施层业务流程图示例技术实现II 功能架构图 -案例功能模块说明1. 船舶监控模块2. 报警管理模块3. 应急响应模块4. 通信管理模块5. 数据分析模块数据管理层基础设施…...
初阶c语言(练习题,猜随机数,关机程序)
目录 第一题,使用函数编写一个随机数,然后自己猜,猜随机数 第二道题(关机程序) 实现代码(关机程序) 实现代码(猜数字) 前言: 学习c语言,学习…...
三维重建(十二)——3D先验的使用
文章目录 零、最近感受和前言一、使用能够快速得到重建初始化的方法1.1 Colmap(多视角)1.2 深度估计(单视角)二、已知形状模板2.1 人脸2.2 人体2.3 动物三、刚性与非刚性约束(变形约束)3.1 刚性变形3.2 非刚性变形四、统计(深度学习)先验——从大量(3D)数据中提取信息…...
DDoS技术解析
这里是Themberfue 今天我们不聊别的,我们聊聊著名的网络攻击手段之一的 DDoS,看看其背后的技术细节。 DoS 了解 DDoS 前,先来讲讲 DoS 是什么,此 DoS 而不是 DOS 操作系统啊。1996年9月6日,世界第三古老的网络服务提供…...
总结:如何在SpringBoot中使用https协议以及自签证书?
总结:如何在SpringBoot中使用https协议以及自签证书? 前提一:什么是http协议?前提二:什么是https协议?一生成自签证书二 将证书转换为PKCS12格式三 配置SpringBoot(1)修改配置文件&a…...
Django开发入门 – 4.创建Django app
Django开发入门 – 4.创建Django app Create A Django App Under An Existing Project By JacksonML 1. 什么是Django app? Django项目面向Web应用程序,它会由一个或多个子模块组成,这些子模块称为apps。 Django apps负责执行完整Web应用程序中涉及…...
安装WPS后,导致python调用Excel.Application异常,解决办法
在使用xlwings编辑excel文件时,默认调用的是“Excel.Application”,如果安装过wps,会导致该注册表为WPS,会导致xlwings执行异常 因为安装过WPS,导致与Excel不兼容的问题,想必大家都听说过。有些问题及时删…...
语言大模型基础概念 一(先了解听说过的名词都是什么)
SFT(监督微调)和RLHF(基于人类反馈的强化学习)的区别 STF(Supervised Fine-Tuning)和RLHF(Reinforcement Learning from Human Feedback)是两种不同的模型训练方法,分别…...
理解 WebGPU 的入口: navigator.gpu
在现代 Web 开发中,WebGPU 已经成为实现高性能图形渲染和计算的强大工具。作为 WebGPU API 的入口点, navigator.gpu 是开发者与 GPU 交互的起点。本文将详细介绍 navigator.gpu 的属性和方法,以及如何通过它初始化 WebGPU 环境。 什…...
Django 创建第一个项目
Django 创建第一个项目 引言 Django 是一个高级的 Python Web 框架,它鼓励快速开发和干净、实用的设计。本指南将带您从头开始创建一个简单的 Django 项目,以便您能够熟悉 Django 的基本结构和概念。 准备工作 在开始之前,请确保您已经安装了 Python 和 Django。以下是安…...
ChatGPT vs DeepSeek详细对比
💡 AI模型发展背景 OpenAI的GPT系列需要数据参数算力,这些要素共同推动了模型的成长。但是,到了GPT-5时代,人类现有的知识精华几乎被学习殆尽,模型的提升空间变得有限。于是OpenAI团队另辟蹊径,尝试模拟人…...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...
