React原理之Fiber双缓冲

前置文章:

  1. React原理之 React 整体架构解读
  2. React原理之整体渲染流程
  3. React原理之Fiber详解

-----读懂这一篇需要对 React 整体架构和渲染流程有大致的概念 😊-----

在前面的文章中,简单介绍了 Fiber 架构,也了解了 Fiber 节点的概念。

Fiber 节点是 Fiber 架构的核心概念之一,它是一种虚拟 DOM 的实现方式。

Fiber 本质上是一个对象, 使用了链表结构

双重缓冲是一种渲染优化技术,其使用两个 Fiber 树来管理渲染,即当前树 current tree工作树 work-in-progress tree。当前树代表屏幕上当前显示的内容,而工作树用于准备下一次的渲染更新,用以实现平滑的更新。

本篇将详细介绍 Fiber 架构的工作原理,即如何使用“双缓存”来完成 Fiber 树的构建与替换

对于 fiber,我们已经有一些了解了。那么 fiber 节点构成的 fiber 树和页面上的 DOM 树有什么关系呢?我们经常看到的 fiber 双缓冲是什么?

双缓冲的概念

双缓冲(Double Buffering)是一种在计算机图形学和用户界面设计中常用的技术,简单来说,就是通过将绘制和显示过程分离,改善图像渲染的流畅性和视觉效果。

在这里插入图片描述

如上图,普通的绘图方式就像是直接在电脑屏幕上画图,用户可以看到绘图的每一个步骤,这样不太优雅。

双缓冲就类似于首先在内存上创建一个“虚拟屏幕”,所有的图形绘制工作都在虚拟屏幕上完成。这个虚拟屏幕就像是一个幕后的画布,绘图或称首先在这个虚拟屏幕上进行,用户看不到绘图的过程。

当虚拟屏幕上的图形绘制完成时,绘图程序会迅速将整个画面一次性拷贝到电脑屏幕上,替换掉之前的画面,这个拷贝过程是瞬间完成的。

这样,用户在屏幕上看到的图像始终都是完整的。

React 中的双缓冲 fiber 树

在 React 源码中,很多方法都需要接收两颗 FiberTree:

function cloneChildFibers(current, workInProgress) {
	// ...
}

current 是当前屏幕上显示内容对应的 FiberNode,workInProgress 指的是正在内存中构建的 FiberNode。

两个 FiberNode 会通过 alternate 属性相互指向:

current.alternate = workInProgress;
workInProgress.alternate = current;

每次状态更新都会产生新的workInProgress Fiber Tree,通过currentworkInProgress的替换,完成DOM更新。

可以从首次渲染(mount)更新(update)这两个阶段来看一下 FiberTree 的构建/替换流程。

首次渲染(mount)

首先我们先了解一下几个概念:

  • fiberRootNode:整个应用的根节点,fiberRootNodecurrent会指向当前页面上已渲染内容对应Fiber树,即current Fiber Tree

  • hostRootFiber: 它是一个具体的 Fiber 节点实例,具有 Fiber 节点的所有属性和方法。通常包含指向宿主环境(如 DOM)的引用,并且负责协调 React 组件与宿主环境之间的交互。

  • rootFiber:一个通用术语,用来指代 Fiber 树的根节点,包括HostRootFiber,其他类型的根 Fiber 等。

  • workInProgress Fiber Tree: 内存中构建的树,简写 WIP FiberTree。

  • current Fiber Tree: 页面显示的树。

// 示例
function App() {
	const [num, setNum] = useState(0);
	return <p onClick={() => setNum((prevNum) => prevNum + 1)}>{num}</p>;
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
流程一:

当执行 ReactDOM.createRoot 时:

// ReactFiberRoot.js 伪代码
function createFiberRoot() {
	//...

	// 创建 FiberRootNode 实例
	const root = new FiberRootNode(/* 参数 */);
	// 创建 HostRootFiber 实例
	const uninitializedFiber = createHostRootFiber(/* 参数 */);
	// 将 HostRootFiber 设置为 FiberRoot 的 current 属性
	root.current = uninitializedFiber;

	// ...
	return root;
}

此时会创建 fiberRootNode 和 hostRootFiber,fiberRootNode 通过 current 来指向 hostRootFiber。

即创建如下的结构:

在这里插入图片描述

由于是首屏渲染,页面中还没有挂载任何DOM,所以fiberRootNode.current指向的rootFiber没有任何子Fiber节点(即 current Fiber Tree 为空)。

流程二 (render)

接下来进入render阶段,根据组件返回的 JSX 在内存中以深度优先原则依次创建wip FiberNode并连接在一起构建 Fiber 树,即workInProgress Fiber Tree

在这里插入图片描述

生成的 wip FiberTree 里面的每一个 FiberNode 会和 current FiberTree 里面的 FiberNode 通过alternate进行关联。但是目前 currentFiberTree 里面只有一个 HostRootFiber,因此就只有这个 HostRootFiber 进行了 alternate 的关联。

流程三 (commit)

当 wip FiberTree 生成完毕后,进入 commit 阶段,此时 FiberRootNode 就会被传递给 Renderer(渲染器),接下来就是进行渲染工作。已构建完的workInProgress Fiber Tree在此阶段渲染到页面。

渲染工作完毕后,浏览器中就显示了对应的 UI,此时 FiberRootNode.current 就会指向这颗 wip Fiber Tree,曾经的 wip Fiber Tree 它就会变成 current FiberTree,完成了双缓存的工作:

在这里插入图片描述

更新(update)

点击p节点触发状态改变而更新,这样就进入了 update。

流程四 (render)

update 会开启一次新的render阶段并构建一棵新的workInProgress Fiber Tree,流程和前面一样。

新的 wip Fiber Tree 里面的每一个 FiberNode 和 current Fiber Tree 的每一个 FiberNode 通过 alternate 属性进行关联。

在这里插入图片描述

流程五 (commit)

当 wip Fiber Tree 生成完毕后, workInProgress Fiber Tree就完成了render阶段的构建,进入commit阶段渲染到页面上。

在这里插入图片描述

FiberRootNode 会被传递给 Renderer 进行渲染,此时宿主环境所渲染出来的真实 UI 对应的就是左边 Fiber Tree (此时还是 wip Fiber Tree) 对应的 DOM 结构,FiberRootNode.current 就会指向左边这棵树,右边的树就再次成为了新的 wip Fiber Tree。

以上两棵 fiber 树交替并更新 DOM 的过程这就是 fiber 双缓冲的原理。

扩展

在构建 workInProgress Fiber Tree 时会尝试复用 current Fiber Tree 中对应的 FiberNode 的数据,这个决定是否复用的过程就是 Diff 算法。留个位置放以后讲 Diff 算法的 🔗~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

macOS安装搭建python环境

安装Homebrew apt-get是一个常见于Debian和Ubuntu等基于Linux的操作系统中的包管理工具&#xff0c;用于安装、更新和移除软件包。然而&#xff0c;macOS使用的是Homebrew或者MacPorts等其他的包管理工具&#xff0c;并不使用apt-get。 如果你想在macOS上使用类似apt-get的功…

书生大模型实战营-进阶关-Lagent 自定义你的 Agent 智能体

Lagent 自定义你的 Agent 智能体 Lagent 介绍环境配置Lagent Web体验第1步&#xff0c;启动大模型API服务第2步&#xff0c;启动 Lagent 的 Web页面 基于 Lagent 自定义智能体 Lagent 介绍 Lagent 是一个轻量级、开源的基于大语言模型的智能体&#xff08;agent&#xff09;框…

家里猫毛到处飞怎么办?如何清理?用宠物空气净化器去除猫毛

我家三只布偶原住民&#xff0c;都是掉毛怪&#xff0c;刚好还是不同的颜色&#xff0c;黑的灰的白的...家里和画板似的&#xff0c;每天都被猫毛上色&#xff0c;清扫时超级崩溃。沙发上、床上、地板上这些常见的地方就不用说了&#xff0c;甚至水杯和碗筷边偶尔也能看见猫毛&…

微服务的基本理解和使用

目录​​​​​​​ 一、微服务基础知识 1、系统架构的演变 &#xff08;1&#xff09;单体应用架构 &#xff08;2&#xff09;垂直应用架构 &#xff08;3&#xff09;分布式SOA架构 &#xff08;4&#xff09;微服务架构 &#xff08;5&#xff09;SOA与微服务的关系…

wincc报警如何通过短信发送给手机

单位使用WINCC上位机监控现场&#xff0c;需要把报警信息发送到指定手机上&#xff0c;能否实现&#xff1f;通过巨控GRMOPC系列远程智能控制终端&#xff0c;简单配置即可实现wincc报警短信传送到手机。配置过程无需任何通讯程序&#xff0c;也不要写任何触发脚本。 GRMOPC模…

Java中接口

接口的定义和使用 练习 public abstract class Animal {private String name;private int age;public Animal() {}public Animal(String name, int age) {this.name name;this.age age;}public String getName() {return name;}public void setName(String name) {this.name…

LIN通讯

目录 1 PLinApi.h 2 TLINFrameEntry 结构体 3 自定义函数getTLINFrameEntry 4 TLINScheduleSlot 结构体 5 自定义函数 getTLINScheduleSlot 6 自定义LIN_SetScheduleInit函数 7 自定义 LIN_StartSchedule 8 发送函数 9 线程接收函数 1 PLinApi.h 这是官方头文件 ///…

开源原型设计工具Penpot

Penpot是一个现代化、开源的协同设计平台&#xff0c;专为跨职能团队打造&#xff0c;提供了强大的在线设计和原型制作功能。 以下是对Penpot的详细介绍&#xff1a; 一、平台特点 开源与免费&#xff1a;Penpot是一个完全免费且开放源代码的项目&#xff0c;允许社区贡献和定…

20:【stm32】定时器一:时基单元

时基单元 1、什么是定时器2、时基单元的基本结构2.1&#xff1a;脉冲的来源2.2&#xff1a;预分频器PSC2.3&#xff1a;计数器CNT2.4&#xff1a;update事件与预加载 3、标准库编程3.1&#xff1a;通过定时器中断来设置延迟函数 1、什么是定时器 定时器是一种专门负责定时功能…

45.【C语言】指针(重难点)(H)

目录&#xff1a; 22.函数指针变量 *创建 *使用 *两段代码分析 23.函数指针数组 *基本用法 *作用 往期推荐 22.函数指针变量 *创建 类比数组指针变量的定义&#xff1a;存放数组地址的指针变量&#xff0c;同理函数指针变量存放函数的地址 格式 函数的返回类型 (*指针变量的…

产品帮助中心如何搭建?五步让客户满意度提升100%

一、引言 创建帮助文章的好处是节省了招募大量客户联系代理的昂贵成本。它们现在通过解决客户的早期问题而无需支持干预&#xff0c;并为自助提供逐步指导&#xff0c;从而取代了支持代理。 当您创建帮助文章时&#xff0c;您会构建知识库并为将来保留它。这些帮助文章充当新…

作业帮 TiDB 7.5.x 使用经验

作者&#xff1a; 是我的海 原文来源&#xff1a; https://tidb.net/blog/5f9784d3 近期在使用 TiDB 时遇到的一些小问题的梳理总结&#xff0c;大部分版本都在6.5.6和7.5.2 1、limit 导致的扫描量过大的优化 研发定时任务每天需要扫描大量数据&#xff0c;到时机器网卡被…

开放式耳机好还是入耳式耳机好?2024五款热销开放式耳机推荐!

开放式耳机与入耳式耳机各有优缺点&#xff0c;适合不同的使用场景和用户需求。 开放式耳机的优点主要包括&#xff1a; 1. 佩戴舒适性好&#xff0c;由于设计宽松&#xff0c;不会给耳朵带来压迫感&#xff0c;适合长时间使用 。 2. 透气性能好&#xff0c;尤其在夏天或运动…

《江南:在爱开始的地方等你》将上映 赖雨濛刘冬沁演绎刻骨之恋

在等到你之前&#xff0c;我们的故事一直未完待续。 用这句话来诠释电影《江南&#xff1a;在爱开始的地方等你》最为精准不过&#xff0c;该片改编自康锐原创小说《月落姑苏》&#xff0c;由康锐导演、编剧&#xff0c;赖雨濛、刘冬沁领衔主演、朱丹妮、王沛为、金巧巧、阎青…

Linux/Windows下线程间通信机制及其API总结

线程间通信&#xff08;Thread Inter-Communication, TIC&#xff09;是指在一个进程内的多个线程之间进行数据交换和同步的方法。与进程间通信相比&#xff0c;线程间通信通常更简单、更高效&#xff0c;因为它们共享相同的内存空间。下面是一些常见的线程间通信机制及其相关A…

vue-element-admin解决三级目录的KeepAlive缓存问题(详情版)

vue-element-admin解决三级目录的KeepAlive缓存问题&#xff08;详情版&#xff09; 本文章将从问题出现的角度看看KeepAlive的缓存问题&#xff0c;然后提出两种解决方法。本文章比较详细&#xff0c;如果只是看怎么解决&#xff0c;代码怎么改&#xff0c;请前往配置版。 一…

【原创教程】电气电工07:网线的制作方法

电气电工经常会遇到做网线,我们做网线需要网线钳与测试仪。需要了解网线的两种接线标准。 我们来看一下网线钳的操作步骤: 这种压线钳也同时具有剥线、剪线功能。 用这种网线钳能制作RJ45网络线接头。RJ11电话线接头、4P电话线接头。适用于RJ45,RJ11型网线 做网线的时候我…

Temu全托管和半托管的区别:一文说清temu全托和半托的差异

TEMU在今年3月再出王炸&#xff0c;上线半托管模式。这是TEMU继全托管模式爆火跨境圈之后的又一个大动作。那么&#xff0c;TEMU全托管和TEMU半托管有哪些不同&#xff1f;卖家朋友应该如何选择呢&#xff1f;今天给大家详细拆解一下。 TEMU全托管和半托管有什么区别 首先是定…

汇编语言lea指令取数组偏移地址

最近看到一条指令&#xff0c;x86汇编&#xff0c; LEA BX, 6[DI] 根据资料&#xff0c;它的含义是&#xff0c;某数组含20个元素&#xff0c;每个元素占一个字节&#xff0c;序号为0~19。设DI指向数组开头处&#xff0c;把序号为6的元素的偏移地址送到BX中&#xff1b; lea指令…

如何进行长截图的两种方法

前言 本文主要讲2种截图方式&#xff0c;分别是谷歌和QQ。 谷歌分为Web端 和 移动端&#xff0c;选一种即可。 第一种&#xff1a;谷歌浏览器控制台自带的 1.先把控制台语言更改为中文&#xff0c;方便查看 ①.按F12&#xff0c;点击设置面板 ②.修改语言为中文并关闭 ③.点击…