React源码分析(一)Fiber
前言
本次React源码参考版本为17.0.3。
React架构前世今生
查阅文档了解到, React@16.x是个分水岭。
React@15及之前
在16之前,React架构大致可以分为两层:
- Reconciler: 主要职责是对比查找更新前后的变化的组件;
- Renderer: 主要职责是基于变化渲染页面;
但是React团队意识到这样的架构有致命问题: 因为在React15中,组件的更新是基于递归查找实现的,这样一旦开始递归,是没有办法中断的,如果组件层级很深,就会出现性能问题,导致页面卡顿。
React@16及之后
为了解决这样的问题,React团队在React@16进行了重构,引入了新的架构模型:
- Reconciler: 主要职责是对比查找更新前后的变化的组件;
- Renderer: 主要职责是基于变化渲染页面;
- Scheduler: 主要职责是区分任务优先级,优先执行高优先级的任务;
新的架构在原来的基础上引入了Scheduler(调度器),这个东西是React团队参考浏览器的API:requestIdleCallback实现的。它的主要作用就是调度更新任务:
- 一方面可以中断当前任务执行更高优先级的任务;
- 另一方面能判断浏览器空闲时间,在恰当的时间将主动权给到浏览器,保证页面性能;并在浏览器下次空闲时继续之前中断的任务; 这样就将之前的不可中断的同步更新变成了异步可中断更新,不直接使用浏览器API可能考虑到兼容问题,可能也有别的方面的考量。
下面是新的React架构更新模型:

这个新的架构在进入Renderer之前的流程是可以被中断的,主要有下列两种情况:
- 进入了更高优先级的任务;
- 浏览器在当前帧没有剩余空闲时间了;
Fiber
Fiber简单的理解就是React15版本的虚拟DOM。
Fiber简单理解
如果将新的React架构比作一个公司,Fiber在新的架构里承担的就是这个公司的员工,员工也有等级,老板,部长,基层,每个人有自己的职责,知道自己在哪个节点该做什么工作,并将未完成的工作记住等第二天上班继续完成,从而保证公司的顺利运行。而每个Fiber对应一个React element:
假如有这样一段代码:
function App() {return (<div><span>牛牛</span><span>不怕困难</span></div>)
}
上面的代码的抽象Fiber树:
其中的每个方块都是一个Fiber,它们通过child, return, sibling连接对方构成一个Fiber树。
Fiber结构
来看一个Fiber会有哪些属性:
function FiberNode(tag, pendingProps, key, mode) {// Instancethis.tag = tag; // 组件类型this.key = key; // 组件props上的keythis.elementType = null; // ReactElement.type 组件的dom类型, 比如`div, p`this.type = null; // 异步组件resolved之后返回的内容this.stateNode = null; // 在浏览器环境对应dom节点this.return = null; // 指向父节点this.child = null; // 孩子节点this.sibling = null; // 兄弟节点, 兄弟节点的return指向同一个父节点this.index = 0;this.ref = null; // refthis.pendingProps = pendingProps; // 新的propsthis.memoizedProps = null; // 上一次渲染完成的propsthis.updateQueue = null; // 组件产生的update信息会放在这个队列this.memoizedState = null; // // 上一次渲染完成的statethis.dependencies = null;this.mode = mode; // Effectsthis.flags = NoFlags; // 相当于之前的effectTag, 记录side effect类型this.nextEffect = null; // 单链表结构, 便于快速查找下一个side effectthis.firstEffect = null; // fiber中第一个side effectthis.lastEffect = null; // fiber中最后一个side effectthis.lanes = NoLanes; // 优先级相关this.childLanes = NoLanes; // 优先级相关this.alternate = null; // 对应的是current fiber
}
Fiber工作原理
在弄明白Fiber工作原理之前,我们要先明确一个认知:新的React架构使用了两个Fiber树。
- 一个Fiber树是当前页面dom的抽象,叫
current; - 另一个Fiber树是在内存中执行更新任务dom的抽象,叫
workInProgress;
这样做是为了方便比对变化组件,并降低创建的成本,尽可能复用现有代码逻辑,从而提高渲染效率。相关参考视频讲解:进入学习
mount
React代码在第一次执行时,因为页面还没有渲染出来,此时是没有current树的,只有一个正在构建DOM的workInProgress树。
假如我们有这样一段代码:
function App() {return (<div><span>牛牛</span><span>不怕困难</span></div>)
}ReactDOM.render(<App/>, document.querySelector('#root'));
基于上面的代码在mount会生成这样的Fiber树:
可以看到这个图只是在前面的图上增加了fiberRoot和rootFiber两个Fiber节点。
- fiberRoot:整个React应用的根节点;
- rootFiber: 某个组件树的根节点;(因为我们可能多次使用
React.render()函数,这样就会有多个rootFiber)
图中此时fiberRoot对应的rootFiber下面还是空的,因为此时是第一次渲染,页面上没有任何东西,当workInProgress树构建完成,在mutation之后,layout之前,fiberRootd的current指针会指向workInProgress树,把它作为新的current树,此时结构会变成这样:
这时页面渲染完成了,等待下次触发更新时会从current树进行拷贝生成workInProgress树,然后比对更新。
update
如果我们在上面的代码中触发更新,将牛牛文本改成了勇敢牛牛,React代码就会开始进行任务调度,因为只有这一个任务,会马上执行,会从current树的rootFiber进行拷贝生成workInProgress树的根节点,在经过向下遍历比对,发现相同的就直接从current树上拷贝复用,直到比对到叶子节点的牛牛文本变了,这时才会生成新的Fiber(这里只是为了方便解释,其实我这里使用的代码牛牛不会生成新的Fiber,因为是纯文本,只会替换父级节点的props)
相关文章:
React源码分析(一)Fiber
前言 本次React源码参考版本为17.0.3。 React架构前世今生 查阅文档了解到, React16.x是个分水岭。 React15及之前 在16之前,React架构大致可以分为两层: Reconciler: 主要职责是对比查找更新前后的变化的组件;R…...
小樽 C++指针—— (壹) 指针变量
(壹) 指针变量 一、指针的概念与定义 二、给指针变量p赋值 三、指针变量的的、-运算 四、无类型指针 五、多重指针 C (壹) 指针变量 小明想把从李华家借来的书——《CCF中学生计算机程序设计》还给李华,但李华不在家,于是把书放到书架第3层的最右边…...
java 代码块 万字详解
概述 : 特点 : 格式 : 情景 : 细节 : 演示 : 英文 : //v,新版编辑器无手动添加目录的功能,PC端阅读建议通过侧边栏进行目录跳转;移动端建议用PC端阅读。😂一、概述 :代码块,也称为初始化块,属于类中的成员&…...
杂项-图片隐写
图片隐写的常见隐写方法: 三基色:RGB(Red Green Blue) 图片文件隐写 1.Firework 使用winhex打开文件时会看到文件头部中包含firework的标识,通过firework可以找到隐藏图片。 使用场景:查看隐写的图片文件…...
【高性价比】初学者入门吉他值得推荐购买的民谣单板吉他品牌—VEAZEN费森吉他
“在未知的世界里,我们是一群不疲不倦的行者,执念于真善美,热衷于事物的极致。我们抽丝剥茧,不断地打败自己,超越自己,我们无所畏惧终将成为巨人。”这是VEAZEN吉他官网首页上很明显的一段话,也…...
2023年浙江交安安全员考试题库及答案
百分百题库提供交安安全员考试试题、交安安全员考试真题、交安安全员证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 50.根据《建设工程安全生产管理条例》第65条规定,施工单位有下列()行…...
【新】华为OD机试 - 跳格子(Python)
跳格子 题目 地上共有 N 个格子,你需要跳完地上所有的格子, 但是格子间是有强依赖关系的,跳完前一个格子后, 后续的格子才会被开启,格子间的依赖关系由多组 steps 数组给出, steps[0] 表示前一个格子, steps[1] 表示 steps[0] 可以开启的格子: 比如 [0,1] 表示从跳完第…...
乡村能做社区团购吗?怎么做?我走访调查后发现机会很大
乡村能做社区团购吗?怎么做?我走访调查后发现机会很大#深度触网 #社区团购 #乡村振兴##乡村旅游##县域经济##市场经济##农文旅产业振兴研究院#乡村旅游能带动农产品加工业、服务业、商贸业等相关联产业的发展 乡村能做社区团购吗?怎么做&…...
态路小课堂丨下一代数据中心100G接口第二篇——SFP-DD封装
100G光模块根据封装模式可分为QSFP28、CXP、CFP、CFP2、FCP4、DSFP和SFP-DD等。态路小课堂之前已经大量介绍了相关内容(。 态路小课堂丨下一代数据中心100G接口——DSFP态路小课堂丨100G解决方案-425G NRZ光模块态路小课堂丨什么是100G QSFP28单波光模块?…...
状态栏和导航栏高度获取
/*** 获取导航栏高度*/public static int getNavigationBarHeight(Context context){int navigationBarHeight 0;int resourceId context.getResources().getIdentifier("navigation_bar_height", "dimen", "android")if (resourceId > 0) {…...
插曲:第一桶金 1w 的来由
因为前天跟同事聊天,发现有个比较严重的认知,就是关于赚钱思维。 同事反馈说工作十来年,却没有接过私活,这里话分两头,有可能私 活钱少,但他给我的理由是:私活太麻烦,有时候不敢接&a…...
中国甲基异丁基甲醇行业头部企业市场占有率及排名调研报告
内容摘要 本文调研和分析全球甲基异丁基甲醇发展现状及未来趋势,核心内容如下: (1)全球市场总体规模,分别按销量和按收入进行了统计分析,历史数据2018-2022年,预测数据2023至2029年。 …...
streamlit自定义组件教程和组件开发环境配置
About create your own component: you can follow this tutorial streamlit tutorial 重要!以下步骤都是在教程的基础上更改的。这个教程做的很棒。 Component development environment configuration: 根据文章 https://streamlit-com…...
Windows CMD常用命令
目录 【打开CMD命令】 【网络测试命令】 ipconfig------查看本机网卡信息 ping------测试网络是否通畅 tracert------追踪路由,也可以用来查看网络连通性 telnet------查看目的主机ip的端口号是否开放 tcping------查看目的主机ip的端口号是否开放 【关于路…...
ChIP-seq 分析:数据比对(3)
读取 reads(二者含义相同,下文不做区分)1. ChIPseq reads 比对 在评估读取质量和我们应用的任何读取过滤之后,我们将希望将我们的读取与基因组对齐,以便识别任何基因组位置显示比对读取高于背景的富集。 由于 ChIPseq…...
并非从0开始的c++之旅 day2
并非从0开始的c之旅 day2一、变量1、 变量名的本质二、程序的内存分区模型1、内存分区运行之前运行之后三、栈区注意事项四、堆区1、堆区使用2、堆区注意事项五、全局变量静态变量1、静态变量2、全局变量六、常量1、全局const常量2、局部const常量七、字符串常量一、变量 既能…...
Linux进阶(Shell编程学习一)
由于shell脚本在java项目运维方面极其重要,比如服务的启动脚本,日志的分割脚本,文件的管理脚本大多都是shell脚本去实现的。所以作为java开发者懂linux的基本命令,会基本的shell编程是必要的。 Shell 是一个用 C 语言编写的程序&…...
sql 优化
sql 优化1. mysql 基础架构1.1 mysql 的组成2. mysql 存储引擎2.1MyISAM2.2 InnoDB2.3 MyISAM 和 InnoDB 的对比3. mysql 索引3.1 Hash 索引3.2 B-Tree 索引3.3 BTree 索引3.4 R-Tree 索引3.5 Full-Text 索引4. sql 优化4.1 避免 select *4.2 避免在where子句中使用or来连接条件…...
第7篇:Java的学习路径
目录 1、Java学习主要内容概览 1.1 Java基础 1.2 数据库技术 1.3 动态网页技术 1.4中间件技术...
对抗生成网络GAN系列——Spectral Normalization原理详解及源码解析
🍊作者简介:秃头小苏,致力于用最通俗的语言描述问题 🍊专栏推荐:深度学习网络原理与实战 🍊近期目标:写好专栏的每一篇文章 🍊支持小苏:点赞👍🏼、…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
面试高频问题
文章目录 🚀 消息队列核心技术揭秘:从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"?性能背后的秘密1.1 顺序写入与零拷贝:性能的双引擎1.2 分区并行:数据的"八车道高速公路"1.3 页缓存与批量处理…...
