【react】理解Fiber

news2024/10/7 9:25:27

Fiber

  • Fiber
    • 概念
    • 结构
    • Fiber 树的遍历是这样发生的【深度遍历】。
    • window.requestIdleCallback()
    • requestAnimationFrame
    • Fiber 是如何工作的
    • 结论
  • 有react fiber,为什么不需要vue fiber

Fiber

概念

JavaScript引擎和页面渲染引擎两个线程是互斥的,当其中一个线程执行时,另一个线程只能挂起等待
如果 JavaScript 线程长时间地占用了主线程,那么渲染层面的更新就不得不长时间地等待,界面长时间不更新,会导致页面响应度变差,用户可能会感觉到卡顿

破解JavaScript中同步操作时间过长的方法其实很简单——分片。

把一个耗时长的任务分成很多小片,每一个小片的运行时间很短,虽然总时间依然很长,但是在每个小片执行完之后,都给其他任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。

React Fiber把更新过程碎片化,每执行完一段更新过程,就把控制权交还给React负责任务协调的模块,看看有没有其他紧急任务要做,如果没有就继续去更新,如果有紧急任务,那就去做紧急任务。

维护每一个分片的数据结构,就是Fiber。

一个 Fiber 代表一个工作单元。

在react中,主要做了以下的操作:

  • 为每个增加了优先级,优先级高的任务可以中断低优先级的任务。然后再重新,注意是重新执行优先级低的任务
  • 增加了异步任务,调用requestIdleCallback api,浏览器空闲的时候执行
  • dom diff树变成了链表,一个dom对应两个fiber(一个链表),对应两个队列,这都是为找到被中断的任务,重新执行

从架构角度来看,Fiber 是对 React核心算法(即调和过程)的重写

从编码角度来看,Fiber是 React内部所定义的一种数据结构,它是 Fiber树结构的节点单位,也就是 React 16 新架构下的虚拟DOM

结构

type Fiber = {
  // 用于标记fiber的WorkTag类型,主要表示当前fiber代表的组件类型如FunctionComponent、ClassComponent等
  tag: WorkTag,
  // ReactElement里面的key
  key: null | string,
  // ReactElement.type,调用`createElement`的第一个参数
  elementType: any,
  // The resolved function/class/ associated with this fiber.
  // 表示当前代表的节点类型
  type: any,
  // 表示当前FiberNode对应的element组件实例
  stateNode: any,

  // 指向他在Fiber节点树中的`parent`,用来在处理完这个节点之后向上返回
  return: Fiber | null,
  // 指向自己的第一个子节点
  child: Fiber | null,
  // 指向自己的兄弟结构,兄弟节点的return指向同一个父节点
  sibling: Fiber | null,
  index: number,

  ref: null | (((handle: mixed) => void) & { _stringRef: ?string }) | RefObject,

  // 当前处理过程中的组件props对象
  pendingProps: any,
  // 上一次渲染完成之后的props
  memoizedProps: any,

  // 该Fiber对应的组件产生的Update会存放在这个队列里面
  updateQueue: UpdateQueue<any> | null,

  // 上一次渲染的时候的state
  memoizedState: any,

  // 一个列表,存放这个Fiber依赖的context
  firstContextDependency: ContextDependency<mixed> | null,

  mode: TypeOfMode,

  // Effect
  // 用来记录Side Effect
  effectTag: SideEffectTag,

  // 单链表用来快速查找下一个side effect
  nextEffect: Fiber | null,

  // 子树中第一个side effect
  firstEffect: Fiber | null,
  // 子树中最后一个side effect
  lastEffect: Fiber | null,

  // 代表任务在未来的哪个时间点应该被完成,之后版本改名为 lanes
  expirationTime: ExpirationTime,

  // 快速确定子树中是否有不在等待的变化
  childExpirationTime: ExpirationTime,

  // fiber的版本池,即记录fiber更新过程,便于恢复
  alternate: Fiber | null,
}

在这里插入图片描述

// 指向父级Fiber节点
this.return = null;
// 指向子Fiber节点
this.child = null;
// 指向右边第一个兄弟Fiber节点
this.sibling = null;

Fiber 树的遍历是这样发生的【深度遍历】。

开始:Fiber 从最上面的 React 元素开始遍历,并为其创建一个 fiber 节点。
子节点:然后,它转到子元素,为这个元素创建一个 fiber 节点。这样继续下去直到在没有孩子
兄弟节点: 现在,它检查是否有兄弟节点元素。如果有,它就遍历兄弟节点元素,然后再到兄弟姐妹的叶子元素。
返回:如果没有兄弟节点,那么它就返回到父节点。

window.requestIdleCallback()

该方法将在浏览器的空闲时段内调用的函数排队。方法提供 deadline,即任务执行限制时间,以切分任务,避免长时间执行,阻塞UI渲染而导致掉帧;
【安排低优先级或非必要的函数在帧结束时的空闲时间被调用】

requestAnimationFrame

安排高优先级的函数在下一个动画帧之前被调用

Fiber 是如何工作的

  1. ReactDOM.render() 和 setState 的时候开始创建更新。

  2. 将创建的更新加入任务队列,等待调度。

  3. 在 requestIdleCallback 空闲时执行任务。

  4. 从根节点开始遍历 Fiber Node,并且构建 WokeInProgress Tree。

  5. 生成 effectList。

  6. 根据 EffectList 更新 DOM。

当调用render和setState方法进行组件渲染和更新的时候,react会经历俩个阶段:reconciler和render阶段:

  • 调和阶段(Reconciler):官方解释。React 会自顶向下通过递归,遍历新数据生成新的 Virtual DOM,然后通过 Diff 算法,找到需要变更的元素(Patch),放到更新队列里面去。

  • 渲染阶段(Renderer):遍历更新队列,通过调用宿主环境的API,实际更新渲染对应元素。宿主环境,比如 DOM、Native、WebGL 等。

React15 最大的问题就是,Reconciler(协调)阶段产生产生虚拟DOM是通过深度优先递归的,并且中途不可间断。所以假如虚拟DOM很深的话,由于 JS线程和浏览器 GUI 线程是互斥的,处理 js 的时间过长,会导致浏览器刷新的时候掉帧,造成卡顿。
而 React16则实现了异步的可中断的更新。

Fiber 使用 requestAnimationFrame 来处理优先级较高的更新,使用 requestIdleCallback 处理优先级较低的更新。因此,在调度工作时,Fiber 检查当前更新的优先级和 deadline (帧结束后的自由时间)。

如果优先级高于待处理的工作,或者没有 截止日期 或者截止日期尚未到达,Fiber 可以在一帧之后安排多个工作单元。而下一组工作单元会被带到更多的帧上。这就是使 Fiber 有可能暂停、重用和中止工作单元的原因。

那么,让我们看看在预定的工作中实际发生了什么。有两个阶段来完成工作。render 和 commit。

渲染阶段
实际的树形遍历和 deadline 的使用发生在这个阶段。这是 Fiber 的内部逻辑,所以在这个阶段对 Fiber 树所做的改变对用户来说是不可见的。因此,Fiber 可以暂停、中止或分担多个框架的工作。

我们可以把这个阶段称为协调阶段。 fiber 从 fiber 树的根部开始遍历,处理每个 fiber 。每一个工作单位都会调用workLoop 函数来执行工作。我们可以把这个工作的处理分成两个步骤。begin 和 complete 。

开始阶段
如果你从 React 代码库中找到 workLoop 函数,它就会调用 performUnitOfWork,它把 nextUnitOfWork 作为一个参数,它就只是个工作的单位,将被执行。 performUnitOfWork 函数内部调用 beginWork 函数。这是 fiber 上发生实际工作的地方,而 performUnitOfWork 只是发生迭代的地方。

在 beginWork 函数中,如果 fiber 没有任何待处理的工作,它就会直接跳出(跳过) fiber 而不进入开始阶段。这就是在遍历大树时, fiber 跳过已经处理过的 fiber ,直接跳到有待处理工作的 fiber 。如果你看到大的 beginWork 函数代码块,我们会发现一个开关块,根据 fiber 标签,调用相应的 fiber 更新函数。就像 updateHostComponent 用于宿主组件。这些函数会更新 fiber 。

如果有子 fiber ,beginWork函数返回子 fiber ,如果没有子 fiber 则返回空。函数 performUnitOfWork 持续迭代并调用子 fiber ,直到叶节点到达。在叶子节点的情况下,beginWork 返回 null,因为没有任何子节点,performUnitOfWork 函数调用 completeUnitOfWork 函数。现在让我们看看完善阶段。

完善阶段
这个 completeUnitOfWork 函数通过调用一个 completeWork 函数来完成当前单位的工作。如果有的话,completeUnitOfWork 会返回一个同级的 fiber 来执行下一个工作单元,如果没有工作的话,则会完成 return(parent) fiber 。这将一直持续到返回值为空,也就是说,直到它到达根节点。和 beginWork 一样,completeWork 也是一个发生实际工作的函数,而 completeUnitOfWork 是用于迭代的。

渲染阶段的结果会产生一个效果列表(副作用)。这些效果就像插入、更新或删除宿主组件的节点,或调用类组件节点的生命周期方法。这些 fiber 被标记为各自的效果标签。

在渲染阶段之后,Fiber 将准备提交更新。

提交阶段
这是一个阶段,完成的工作将被用来在用户界面上渲染它。由于这一阶段的结果对用户来说是可见的,所以不能被分成部分渲染。这个阶段是一个同步的阶段。

在这个阶段的开始,Fiber 有已经在 UI 上渲染的 current 树,finishedWork,或者在渲染阶段建立的 workInProgress 树和效果列表。

effect 列表是 fiber 的链表,它有副作用。所以,它是渲染阶段的 workInProgress 树的节点的一个子集,它有副作用(更新)。effect 列表的节点是用 nextEffect 指针链接的。

在这个阶段调用的函数是 completeRoot。

在这里,workInProgress 树成为 current 树,因为它被用来渲染 UI。实际的 DOM 更新,如插入、更新、删除,以及对生命周期方法的调用或者更新相对应的引用 —— 发生在 effect 列表中的节点上。

这就是 fiber 协调器的工作方式。

结论

这就是 React Fiber 协调器使之有可能将工作分为多个工作单元。它设置每个工作的优先级,并使暂停、重用和中止工作单元成为可能。在 fiber 树中,单个节点保持跟踪,这是使上述事情成为可能的需要。每个 fiber 都是一个链表的节点,它们通过子、兄弟节点和返回引用连接起来。

有react fiber,为什么不需要vue fiber

  • “我们现在已经知道了react fiber是在弥补更新时“无脑”刷新,不够精确带来的缺陷。”fiber不是用来弥补无脑刷新的,fibe是用来让原来同步的调用颗粒化的,解决无脑刷新你应该用meno
  • vue不需要fiber是因为他使用nextTick来异步决定什么时候执行renderfunction 本质上思路是和react一致的和响应式原理没有半毛钱关系

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

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

相关文章

12月 被大厂以“人员优化”的名义 无情的辞退了...

前几天&#xff0c;一个认识了好几年在大厂工作的测试员朋友&#xff0c;年近30了&#xff0c;却被大厂以“人员优化”的名义无情被辞&#xff0c;据他说&#xff0c;有一个月散伙饭都吃了好几顿…… 在很多企业&#xff0c;都有KPI考核&#xff0c;然后在此基础上还会弄个“…

IB EE 学习干货,从选学科/课题/写稿/对稿/交稿几个方面入手分享

本文从选学科&#xff0c;选课题&#xff0c;写稿&#xff0c;对稿&#xff0c;交稿几个方面入手分享。关于不同学科的EE&#xff0c;本文涵盖了数学和物理EE&#xff08;因为我们猜很多同学们都选了这两个学科的EE&#xff09;。 文中分享的学习方法都是我们从个人经历出发&am…

微服务 @SentinelResource 服务网关

微服务 SentinelResource 服务网关SentinelResourceFeign整合Sentinel什么场景下需要Feign集合Sentinel呢&#xff1f;服务网关为什么需要网关网关组件Gateway快速入门什么是Gateway操作示例自定义路由规则SentinelResource 自定义异常返回是对所有的情况进行统一处理&#xf…

DTC补货实战:从算法到落地

本文作者&#xff1a;凡飞&#xff0c;从快递到快消&#xff0c;一个平凡的供应链算法深耕者。“ 我希望衡量我们ai团队价值的&#xff0c;不是创造了多么精深的算法&#xff0c;而是跨越算法到落地间距离的能力。”近年来随着电商行业从增量市场逐步成长到了存量市场&#xff…

第二章.神经网络—激活函数

第二章.神经网络 感知机存在如何设置合适的权重问题&#xff0c;神经网络的出现就是为了解决感知机存在的问题&#xff0c;神经网络的一个重要性质&#xff1a;它可以自动的从数据中学习到合适的权重参数。 2.1.从感知机到神经网络 1.神经网络示例 1).示意图&#xff1a; 网络…

《技术领导力:程序员如何才能带团队》 读书笔记

技术管理工作 管理者能力 作为技术团队管理者&#xff0c;无论具体管几个人&#xff0c;最好能够拥有以下能力&#xff0c;才能满足各个需求方提出的需求&#xff1a; 深入理解一门或多门编程语言深入理解多种流行的框架系统架构能力强&#xff0c;拥有复杂系统的设计经验积…

Hystrix高可用框架

Hystrix是什么 Hystrix Home,Hystrix是高可用性保障的一个框架。Netflix的API团队从2011年开始做一些提升系统可用性和稳定性的工作,Hystrix就是从那时候开始发展的。在2012年的时候,Hystrix就变得比较成熟和稳定了,Netflix中除了API团队以外,很多其他的团队都开始使用Hy…

vue2.6.10+vite2开启template模板动态编译

在从vue-cli迁移到vite2的时候&#xff0c;之前在代码中使用的模板编译遇到了问题&#xff1a;我在项目中会根据后台返回的内容动态渲染&#xff0c;如果返回内容中有<el-image>等标签&#xff0c;v-html无法识别非html标签&#xff0c;导致图片渲染失败&#xff0c;因此…

基于Springboot搭建java项目(三十二)—— Docker部署java服务

Docker部署java服务 一、Linux服务安装Docker 关于Docker的安装在之前的Linux的三种安装方式的第三种安装方式中有介绍 传送门&#xff1a;https://blog.csdn.net/m0_46616045/article/details/128841396 二、编写DockerFile 1、将需要部署的Jar包放到服务器上 2、编写Doc…

3.【SpringBoot源码】SpringBoot自动配置原理

目录 一、简介 1)、SpringBootConfiguration 2)、ComponentScan 3)、EnableAutoConfiguration 二、AutoConfigurationPackage 三、Import(AutoConfigurationImportSelector.class) 1)、AutoConfigurationImportSelector介绍 2)、自动配置流程 2-1)、ConfigurationClas…

Vue中数组的列表渲染(v-for渲染数组,数组改变,页面不渲染问题)

1.基本的列表&#xff08;v-for的基本使用&#xff09;&#xff1a; <template><!-- v-for指令:1.用于展示列表数据2.语法&#xff1a;v-for"(item, index) in xxx" :key"yyy"3.可遍历&#xff1a;数组、对象、字符串&#xff08;用的很少&#…

计算机网络基础学习指南(二)

4. HTTP协议 简介 5. Socket 5.1 简介 即套接字&#xff0c;是应用层 与 TCP/IP 协议族通信的中间软件抽象层&#xff0c;表现为一个封装了 TCP / IP协议族 的编程接口&#xff08;API&#xff09; Socket不是一种协议&#xff0c;而是一个编程调用接口&#xff08;API&#…

HashMap源码详细解析

HashMap的继承:HashMap实现了Cloneable接口&#xff0c;所以可以被克隆HashMap实现了Serializable接口&#xff0c;可以被序列化HashMap继承了AbstractMap并实现了Map接口&#xff0c;具有Map接口的所有功能存储结构:JDK1.7(包括1.7)之前HashMap底层是数组链表结合而成的高级数…

【深度学习】ReID相关知识点解析(PCB、BoT、MGN)

PCB(Part-based Convolutional Baseline) RPP结构图: 网络流程: 经过一个backbone得到特征图T。T中的每列向量称为f(1,1,c)。 如:输入(384,128,3)经过backbone降采样16倍后得到特征图T(24,8,c)。 将T从上到下切成p(p=6)片。记为P_i(i=1…p)。——测试时接第…

PMP应该如何备考?掌握着三个步骤

在我这里大概就是有三个点需要注意的&#xff1a; 重点一&#xff0c;好好上课 我选择的是线下培训班&#xff0c;一共是6节线下课&#xff0c;每次线下课都占用了周末一整天的时间。 从早上9点到下午5点&#xff0c;没上课前我觉得应该会蛮累的&#xff0c;但实际上下来其实…

linux 安装mysql服务(超详细)

目录 1、查看是否已经安装了mysql 2、下载官方mysql安装包 3、安装MySQL包 4、安装 MySQL 5、启动 Mysql 服务 6、查看mysql运行状态 7、查看初始密码&#xff08;红色部分为初始密码) 8、进入数据库 1.首先关闭mysql服务 2.然后编辑文件&#xff0c;添加代码 3.新增…

什么是散点图?

在之前的文章中&#xff0c;我已经介绍过堆叠条形图、分组条形图和堆叠面积图&#xff0c;本文介绍一些散点图的百科知识。 散点图&#xff0c;顾名思义就是使用一些散乱的点来展示数据的一种图表&#xff0c;这些点在哪个位置&#xff0c;是由其X值和Y值确定的&#xff0c;因此…

【C++】常量引用(常引用)一些经典问题

常量引用1.常量引用错误的案例2.常量引用的前提条件3.分析错误案例4.总结常量引用1.常量引用错误的案例2.常量引用的前提条件3.分析错误案例4.总结1.常量引用错误的案例 1.常量引用的使用的场景一般是用来修饰函数的形参&#xff0c;防止误操作。 比如&#xff1a; //在下列函数…

HTB_Find The Easy Pass

文章目录信息收集分析汇编代码信息收集 下载后是一个加密的zip压缩包&#xff0c;里面是一个exe文件 解压密码获取&#xff1a; 使用zip2john暴破&#xff0c;失败 zip2john Find\ The\ Easy\ Pass.zip >hash.txt john -w/usr/share/wordlists/rockyou.txt hash.txt使用…

DAMA数据管理知识体系指南之数据开发

第5章 数据开发 数据开发&#xff08;Data Development)是数据管理框架中的第三个数据管理职能它是第二个与数据治理功能交互并受其影响的数据管理职能。 5.1 简介 数据开发是指分析、设计、实施、部署及维护数据解决方案&#xff0c;以使企业的数据资源价值最大化。数据开发…