广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >React超详细讲述Fiber的使用
  • 210
分享到

React超详细讲述Fiber的使用

ReactFiber原理ReactFiber优点ReactFiber 2023-02-08 09:02:36 210人浏览 薄情痞子
摘要

目录Fiber概念结构Fiber树的遍历是这样发生的深度遍历window.requestIdleCallback()requestAnimationFrameFiber是如何工作的结

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是如何工作的

  • ReactDOM.render() 和 setState 的时候开始创建更新。
  • 将创建的更新加入任务队列,等待调度。
  • 在 requestIdleCallback 空闲时执行任务。
  • 从根节点开始遍历 Fiber Node,并且构建 WokeInProgress Tree。
  • 生成 effectList。
  • 根据 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一致的和响应式原理没有半毛钱关系

到此这篇关于React超详细讲述Fiber的使用的文章就介绍到这了,更多相关React Fiber内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: React超详细讲述Fiber的使用

本文链接: https://www.lsjlt.com/news/194580.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • React超详细讲述Fiber的使用
    目录Fiber概念结构Fiber树的遍历是这样发生的深度遍历window.requestIdleCallback()requestAnimationFrameFiber是如何工作的结...
    99+
    2023-02-08
    React Fiber原理 React Fiber优点 React Fiber
  • React组件的使用详细讲解
    目录1.组件的创建方式函数式组件class组件2.组件命名规范3.组件传值props接收值(函数式组件)接收值(class组件)4.组件样式sass5.组件的生命周期函数6.受控组件...
    99+
    2022-11-16
    React组件开发 React组件创建 React组件
  • Python超详细讲解元类的使用
    目录类的定义一、什么是元类二、注意区分元类和继承的基类三、type 元类的使用四、自定义元类的使用类的定义 对象是通过类创建的,如下面的代码: # object 为顶层基类 clas...
    99+
    2022-11-11
  • Java超详细讲解ThreadLocal类的使用
    目录Threadlocal有什么用:ThreadLocal使用实例API介绍ThreadLocal的使用Threadlocal 的源码分析原理源码内部类ThreadLocalMapT...
    99+
    2022-11-13
  • C++超详细讲解模板的使用
    目录一、函数模板1.1函数模板概念1.2 函数模板格式1.3 函数模板的原理1.4 函数模板的实例化二、类模板2.1 类模板的定义格式2.2类模板的实例化总结一、函数模板 1.1函数...
    99+
    2022-11-13
  • C++超详细讲解友元的使用
    目录一、友元的概念二、友元的用法三、友元的语法四、友元的尴尬五、注意事项六、小结一、友元的概念 什么是友元友元是 C++ 中的一种关系友元关系发生在函数与类之间或者类与类之间友元关系...
    99+
    2022-11-13
  • React详细讲解JSX和组件的使用
    目录一、React JSX1.1 JSX简介1.2 JSX表达式1.3 JSX条件表达式1.4 JSX循环表达式1.5 JSX样式表达式1.6 JSX注释表达式二、React组件2....
    99+
    2022-11-13
  • Android超详细讲解fitsSystemWindows属性的使用
    对于android:fitsSystemWindows这个属性你是否感觉又熟悉又陌生呢? 熟悉是因为大概知道它可以用来实现沉浸式状态栏的效果,陌生是因为对它好像又不够了解,这个属性经...
    99+
    2022-11-13
  • C++超详细讲解auto与nullptr的使用
    目录一. auto关键字1. auto介绍2. 使用规则3. auto不能推导的场景二. 基于范围的for循环(C++11)1. 范围for的语法2. 范围for的使用条件三. 指针...
    99+
    2022-11-13
  • C++ 超详细示例讲解list的使用
    目录一、list的介绍list的介绍二、list的使用2.1 list的构造函数2.2 list迭代器的使用2.3 list相关的容量大小相关的函数2.4 list数据的访问相关的函...
    99+
    2022-11-13
  • C++ 超详细讲解stack与queue的使用
    目录stack介绍和使用模拟实现stack的使用例题最小栈栈的弹出压入序列逆波兰表达式求值queue模拟实现容器适配器deque简介priority_queue优先级队列priori...
    99+
    2022-11-13
  • Android超详细讲解组件AdapterView的使用
    目录概述 介绍AdapterView的编程模式 Adapter ListView使用myAdapater.javaMainActivity.javamy...
    99+
    2022-11-13
  • Android超详细讲解组件ScrollView的使用
    目录概述练习HorizontalScrollView:概述     ScrollView也是一个容器,它是FrameLayout的子类,它的主要作用就是将超出物理...
    99+
    2022-11-13
  • Android超详细讲解组件LinearLayout的使用
    目录概述常用XML配置属性(1) android:orientation(2) android:gravity(3) View中继承来的属性代码举例概述 LinearLay...
    99+
    2022-11-13
  • C++BoostLockfree超详细讲解使用方法
    目录一、说明二、示例和代码Boost.Lockfree 一、说明 Boost.Lockfree 提供线程安全和无锁容器。可以从多个线程访问此库中的容器,而无需同步访问。 在 1.56...
    99+
    2022-11-21
    C++ Boost Lockfree C++ Lockfree方案
  • PyTorch Dataset与DataLoader使用超详细讲解
    目录一、Dataset1. 在控制台进行操作①获取图片的基本信息②获取文件的基本信息2. 编写一个继承Dataset 的类加载数据①定义 MyData类②创建类的实例并调用二、Dat...
    99+
    2022-11-11
  • MySql超详细讲解表的用法
    目录1. 建表的语法2. mysql中的数据类型3. 模拟表4. 创建一个学生表1. 创建表(create-DDL)2. 插入数据(insert-DML)3. 插入日期4. date和datetime的区别5. 更新(u...
    99+
    2022-09-16
  • C语言超详细讲解指针的使用
    目录指针概述自身类型指向类型代码例子数值型指针字符型指针单字符字符数组字符串型指针字符数组总结指针概述 C语言中指针也可以认为是一种类型,不同于数值型和字符型的类型。推演过去指针变量...
    99+
    2022-11-13
  • Reactjsx转换与createElement使用超详细讲解
    目录jsx的转换16.x版本及之前17.x版本及之后React.createElement源码React.Component 源码总结jsx的转换 我们从 react 应用的入口开始...
    99+
    2022-11-13
    React jsx转换 React createElement
  • C++ Boost Lockfree超详细讲解使用方法
    Boost Lockfree 是一个基于 C++ 的库,用于实现无锁的数据结构和算法。无锁的数据结构和算法是为了解决并发编程中的竞争...
    99+
    2023-08-16
    C++
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作