【React源码解析】深入理解react时间切片和fiber架构

news2024/9/26 3:28:39

时间切片

假如React一个更新需要耗时200ms,我们可以将其拆分为405ms的更新(后续会讲到如何拆分),然后每一帧里只花5ms来执行更新。那么,每一帧里不就剩余16.7 - 5 = 11.7ms的时间可以进行用户事件渲染等其他的js操作吗?如下所示:
image.png
那么这里就有两个问题:

  • 问题1:如何控制每一帧只执行5ms的更新?
  • 问题2:如何控制40个更新分配到每一帧里?

对于问题1比较容易,我们可以在更新开始时记录startTime,然后每执行一小段时间判断是否超过5ms。如果超过了5ms就不再执行,等下一帧再继续执行。

对于问题2,我们可以通过宏任务实现。比如5ms的更新结束了,那么我们可以为下一个5ms更新开启一个宏任务。浏览器则会将这个宏任务分配到当前帧或者是下一帧执行。

注意:
浏览器这一行为是内置的,比如设置 10000 个 setTimeout(fn, 0),并不会阻塞线程,而是浏览器会将这 10000 个回调合理分配到每一帧当中去执行。
比如:10000个个 setTimeout(fn, 0)在执行时,第一帧里可能执行了300个 setTimeout 回调,第二帧里可能执行了400个 setTimeout 回调,第 n 帧里可能执行了 200 个回调。浏览器为了尽量保证不掉帧,会合理将这些宏任务分配到帧当中去。

解决了上面两个问题,那么这个时候我们就有下面这种思路了:

  1. 更新开始,记录开始时间 startTime
  2. js 代码执行时,记录距离开始时间startTime是否超过了 5ms
  3. 如果超过了 5ms,那么这个时候就不应该再以同步的形式来执行代码了,否则依然会阻塞后续的代码执行。
  4. 所以这个时候我们需要把后续的更新改为一个宏任务,这样浏览器就会分配给他执行的时机。如果有用户事件进来,那么会执行用户事件,等用户事件执行完成后,再继续执行宏任务中的更新。

image.png
如上图所示,由于更新拆分成了一个个小的宏任务,从而使得click事件的回调有机会执行。

现在我们已经解决了更新阻塞的问题,接下来就需要解决如何将一个完整的更新拆分为多个更新,并且让它可以暂停等到click事件完成后再回来更新。

Fiber 架构

React传统的Reconciler是通过类似于虚拟DOM的方式来进行对比和标记更新。而虚拟DOM的结构不能很好满足将更新拆分的需求。因为它一旦暂停对比过程,下次更新时,很难找到上一个节点和下一个节点的信息,虽然有办法能找到,但是相对而言比较麻烦。所以,React团队引入了Fiber来解决这一问题。

每一个DOM节点对应一个Fiber对象,DOM树对应的Fiber结构如下:
image.png
(图片来自于这里)
Fiber通过链表的形式来记录节点之间的关系,它与传统的虚拟DOM最大的区别是多加了几个属性:

  • return表示父节点fiber
  • child表示子节点的第一个fiber
  • sibling表示下一个兄弟节点的fiber

通过这种链表的形式,可以很轻松的找到每一个节点的下一个节点或上一个节点。那么这个特性有什么作用呢?

结合上面提到的时间切片的思路,我们需要判断更新是否超过了5ms,我们以上面这棵Fiber树梳理一下更新的思路。从App Fiber开始:

  • 浏览器第一帧:
    • 记录更新开始时间startTime
    • 首先计算App节点,计算完成时,发现更新未超过5ms,继续更新下一个节点。
    • 计算div节点,计算完成时,发现更新超过了5ms,那么不会进行更新,而是开启一个宏任务。
  • 浏览器第二帧:
    • 上一帧最后更新的是div节点,找到下一个节点i am,计算该节点,发现更新未超过5ms,继续更新下一个节点。
    • 计算span节点,发现更新超过了5ms,那么不会进行更新,而是开启一个宏任务。
  • 浏览器第三帧:
    • 上一帧最后更新的是span节点,找到下一个节点KaSong,计算该节点,更新完成。

image.png

注:

  1. 实际的更新过程是 beginWork / completeWork 递与归的阶段,与这里有出入,这里仅做演示介绍。
  2. 这里的更新过程有可能不是第二帧和第三帧,而是在一帧里执行完成,具体需要看浏览器如何去分配宏任务。
  3. 更新过程分为 reconciler 和 commit 阶段,这里只会将 reconciler 阶段拆分。而 commit 阶段是映射为真实 DOM,无法拆分。

对应浏览器中的执行过程如下:
image.png
在这个过程中,每个节点计算完成后都会去校验更新时间是否超过了5ms,然后找到下一个节点继续计算,而双向链表恰恰是切合这种需求。

小结

通过上面的分析,我们可以总结成以下思路:

  1. 更新时遍历更新每一个节点,每更新一个Fiber节点后,会判断累计更新时间是否超过5ms
  2. 如果超过5ms,将下一个更新创建为一个宏任务,浏览器自动为其分配执行时机,从而不阻塞用户事件等操作。
  3. 如果更新的过程中,用户进行触发了点击事件,那么会在5ms与下一个5ms的间隙中去执行click事件回调。

通过以上步骤,我们能够将现有的同步更新转变为多个小更新分配到浏览器帧里,并且不会阻塞用户事件。接下来看看在React中实际是如何做到的。

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

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

相关文章

13 Midjourney从零到商用·进阶篇:灯光、角度与风格等精细控制方法

在前面我们了解了提示词的书写,那么如何利用提示词来精确控制生成画面的灯光、角度与风格 呢?在本篇文章中我么一起来探讨一下。 一、灯光 在摄影中,对灯光的要求都是非常高的。灯光能对人物、动物、物体、场景等进行修饰。每一种微小的的灯光…

链接升级:Element UI <el-link> 的应用

链接升级&#xff1a;Element UI 的应用 一 . 创建文字链接1.1 注册路由1.2 创建文字链接 二 . 文字链接的属性2.1 文字链接的颜色2.2 是否显示下划线2.3 是否禁用状态2.4 填写跳转地址2.5 加入图标 在本篇文章中&#xff0c;我们将深入探索Element UI中的<el-link>组件—…

本地不能訪問linux的kafka服務

1.本地使用kafka客戶端工具連接kafka服務&#xff0c;提示連接失敗 2. 本地使用telnet ip port命令也失敗 3.查看zookeeper和kafka服務是否正常 ps -ef | grep zookeeper ps -ef | grep kafka 3.關閉操作系統的防火墻(僅限于測試使用) 3.1.禁用防火墙 systemctl stop firew…

先有正态分布,还是先有高斯函数?

正态分布&#xff08;也称为高斯分布&#xff09;是由德国数学家卡尔弗里德里希高斯在研究天文学中的误差分布时提出的。而高斯函数通常指的是正态分布的概率密度函数&#xff0c;它是描述正态分布特性的一个数学表达式。因此&#xff0c;可以明确地说&#xff0c;是先有正态分…

eureka.client.service-url.defaultZone的坑

错误的配置 eureka: client: service-url: default-zone: http://192.168.100.10:8080/eureka正确的配置 eureka: client: service-url: defaultZone: http://192.168.100.10:8080/eureka根据错误日志堆栈打断电调试 出现两个key&#xff0c;也就是defaultZone不支持snake-c…

Vue: watch5种监听情况

目录 一.watch的性质与作用 1.watch 的性质包括&#xff1a; 2.watch 常用于以下场景&#xff1a; 二.监视ref定义的基本类型数据 三.监视ref定义的对象类型数据 四.监视reactive定义的对象类型数据 五.监视ref或reactive定义的对象类型数据中的某个属性 六.监视上述的…

c++题目_【模板】最小生成树Prim

题目描述 这是一道最小生成树Prim的模板题&#xff0c;本题与【模板】最小生成树Kruskal&#xff0c;仅仅只有nn和mm的大小不同 给出一个无向图&#xff0c;求出最小生成树&#xff0c;如果该图不连通&#xff0c;则输出orz 输入 第一行输入2个正整数n,mn,m&#xff0c;代表…

【自然语言处理】实验三:新冠病毒的FAQ问答系统

目录 前言 1.新建data_process.py 1.1导入包并定义功能模块1用来读取问题和答案FAQ的文件 1.2功能模块2&#xff1a;进行问题/问题列表处理&#xff08;正则化&#xff0c;分词&#xff09; 1.3功能模块3&#xff1a;处理输入的问题 1.4功能模块4&#xff1a;计算输入问题与问题…

Java | Leetcode Java题解之第403题青蛙过河

题目&#xff1a; 题解&#xff1a; class Solution {public boolean canCross(int[] stones) {int n stones.length;boolean[][] dp new boolean[n][n];dp[0][0] true;for (int i 1; i < n; i) {if (stones[i] - stones[i - 1] > i) {return false;}}for (int i 1…

redis windows安装包下载路径

https://github.com/tporadowski/redis/releases 通过网盘分享的文件&#xff1a;Redis-x64-5.0.14.1.zip 链接: https://pan.baidu.com/s/12XQOfKB75yajJ0fJLzl4rQ?pwd1234 提取码: 1234

C++数据结构-树的概念及分类介绍(基础篇)

1.什么是树 树是数据结构中的一种&#xff0c;其属于非线性数据结构结构的一种&#xff0c;我们前文所提到的数据结构多数都是线性的&#xff0c;这也是较为简单的数据结构&#xff0c;而接下来的树与图均属于非线性数据结构&#xff0c;也是概念极多的一类。 树是由结点或顶…

软件设计师容易考吗?

一、软考软件设计师难吗 软考软件设计师考试对于不同的人来说&#xff0c;难度可能有所差异。然而&#xff0c;总体来说&#xff0c;软考软件设计师考试是相对较难的考试&#xff0c;需要考生具备扎实的软件设计理论知识和实践经验。 从各地2024年上半年软考合格人数的公布情…

Python | Leetcode Python题解之第405题数字转换为十六进制数

题目&#xff1a; 题解&#xff1a; CONV "0123456789abcdef" class Solution:def toHex(self, num: int) -> str:ans []# 32位2进制数&#xff0c;转换成16进制 -> 4个一组&#xff0c;一共八组for _ in range(8):ans.append(num%16)num // 16if not num:b…

c++ 红黑树(带头结点)

想必在看到这篇文章的时候&#xff0c;你一定是带着问题去搜索的&#xff0c;一定是对红黑树已经有了初步大致的认识&#xff0c;已经知道了红黑树的性质与普通红黑树的功能与如何代码实现&#xff0c;但是莫一天突然看到了带头结点的红黑树&#xff0c;肯定是对此有一些疑惑的…

linux/ubuntu国内镜像安装gitleaks敏感信息扫描工具教程及避坑点

1、背景 利用gitleaks扫描git仓库或者文件 GitHub上有比较详细的教程&#xff0c;但是由于每个人的安装环境不同&#xff0c;坑很多&#xff0c;网上能查到的有效信息也比较少。这里就以我坑很多的环境为例&#xff0c;捋一下步骤。 GitHub - gitleaks/gitleaks: Protect an…

<<编码>> 第 12 章 二进制加法器--半加器 示例电路

异或门 info::操作说明 鼠标单击逻辑输入切换 0|1 状态 异或门的符号为 或门 符号输入处再添加一道弧线. 异或门的输出等价于将两个输入分别接入一个或门和一个与非门, 再对这两者输出结果取与的结果. 读者可对照着 或门, 与非门 和 与门 的真值表在示例电路中验证这一点. prim…

蓝桥杯单片机STC15F2K60S2第十二届省赛代码详细讲解(附完整代码)

本文是写第十二届的蓝桥杯省赛代码&#xff0c;如果是新手的话&#xff0c;欢迎去观看我专门为新手写的一篇。也欢迎收录该专栏。 蓝桥杯单片机STC15F2K60S2第十三届省赛代码详细讲解&#xff08;附完整代码&#xff09; 专栏&#xff1a; 蓝桥杯单片机 接下来直接上正文。…

初阶数据结构【TOP】- 11.普通二叉树的介绍 - 1. (细致,保姆~~!)

文章目录 前言一、普通二叉树的链式结构二、 造树三、普通二叉树的遍历四、遍历完整代码五、总结 前言 本篇文章笔者将会对普通二叉树部分进行细致的讲解 , 本篇主要包括以下内容: 二叉树链式结构的介绍 ,二叉树的遍历. 笔者会一步一步分析带学者领略递归的美好~~ 一、普通二叉…

4.接口测试基础(Jmter工具/场景二:一个项目由多个人负责接口测试,我只负责其中三个模块,协同)

一、场景二&#xff1a;一个项目由多个人负责接口测试&#xff0c;我只负责其中三个模块&#xff0c;协同 1.什么是测试片段&#xff1f; 1&#xff09;就相当于只是项目的一部分用例&#xff0c;不能单独运行&#xff0c;必须要和控制器&#xff08;include,模块&#xff09;一…

驾驶员注意力分神状态检测系统源码分享

驾驶员注意力分神状态检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of …