我的编程空间,编程开发者的网络收藏夹
学习永远不晚

react fiber执行原理示例解析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

react fiber执行原理示例解析

为什么要使用fiber,要解决什么问题?

react16 引入 Fiber 架构之前,react 会采用递归方法对比两颗虚拟DOM树,找出需要改动的节点,然后同步更新它们,这个过程 react 称为reconcilation(协调)。在reconcilation期间,react 会同步执行操作,提交到真实 DOM 的更改,会一直占着浏览器的资源,不能中断,中断后就不能恢复,使得我们一些用户操作定时器等等事件无法得到响应,是一个非常糟糕的用户体验。

所以我们要解决的问题就是:解决React主线程长时间占用的一个问题。 这个时候,就引入了Fiber架构。

fiber是什么?

Fiber 可以理解为是一个执行单元,也可以理解为是一种数据结构。每一个React元素都对应一个fiber对象,我们先看看fiber中的属性:

function FiberNode(
  tag: WorkTag,
  pendingProps: mixed,
  key: null | string,
  mode: TypeOfMode,
) {
  // 作为静态数据结构的属性
  this.tag = tag;	     // Fiber对应组件的类型 Function/Class/Host...
  this.key = key;	     // key属性
  this.elementType = null;   // 大部分情况同type,某些情况不同,比如FunctionComponent使用React.memo包裹
  this.type = null;					// 对于 FunctionComponent,指函数本身,对于ClassComponent,指class,对于HostComponent,指DOM节点tagName
  this.stateNode = null;		// Fiber对应的真实DOM节点
  // 用于连接其他Fiber节点形成Fiber树
  this.parent = null;		// 指向父级Fiber节点
  this.child = null;		// 指向子Fiber节点
  this.sibling = null;	// 指向右边第一个兄弟Fiber节点
  this.index = 0;
  this.ref = null;
  // 作为动态的工作单元的属性 —— 保存本次更新造成的状态改变相关信息
  this.pendingProps = pendingProps;
  this.memoizedProps = null;
  this.updateQueue = null;		// class 组件 Fiber 节点上的多个 Update 会组成链表并被包含在 fiber.updateQueue 中。 函数组件则是存储 useEffect 的 effect 的环状链表。
  this.memoizedState = null;	// hook 组成单向链表挂载的位置
  this.dependencies = null;
  this.mode = mode;
  // Effects
  this.flags = NoFlags;
  this.subtreeFlags = NoFlags;
  this.deletions = null;
  // 调度优先级相关
  this.lanes = NoLanes;
  this.childLanes = NoLanes;
  // 指向该fiber在另一次更新时对应的fiber
  this.alternate = null;
}

数据结构

React Fiber 就是采用链表实现的,主要就是通过以下这几个属性表示:

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

假如我们要渲染下面这个元素树:

<div>
    <h1>
        <p>
            <a></a>
        </p>
    </h1>
    <h2></h2>
</div>

我们看一下它的Fiber结构树:

每个fiber元素都有这三个属性,观察上面图发现:

  • parent:指向父级Fiber节点:
  • child:指向子Fiber节点
  • sibling:指向右边的兄弟节点

执行单元

我们可以把每个fiber当做一个执行单元,每次执行完一个执行单元。React会去检测还剩多少时间,如果没有时间就将控制权让给浏览器,如果还有时间就去执行下一个执行单元。
这里就涉及到了一个问题,react如何和浏览器进行控制权的交接,浏览器何时空闲呢?。我们先来了解一下浏览器的工作:

浏览器工作:

在浏览器中,我们所看到的页面是一帧一帧画出来的,渲染的帧率与设备的刷新率保持一致。通常情况下,我们的设备都是60Hz,也就是说,1s屏幕会刷新60次。当每秒内绘制的帧数(FPS)超过60时,页面渲染是流畅的,当帧数小于60时,会明显感受到卡顿。下面来看完整的一帧中,浏览器具体做了哪些事情:

  • 首先需要处理输入事件,能够让用户得到最早的反馈
  • 接下来是处理定时器,需要检查定时器是否到时间,并执行对应的回调
  • 接下来处理 Begin Frame(开始帧),即每一帧的事件,包括 window.resizescrollmedia query change
  • 接下来执行请求动画帧 requestAnimationFrame(rAF),即在每次绘制之前,会执行 rAF 回调
  • 紧接着进行 Layout 操作,包括计算布局和更新布局,即这个元素的样式是怎样的,它应该在页面如何展示
  • 接着进行 Paint 操作,得到树中每个节点的尺寸与位置等信息,浏览器针对每个元素进行内容填充
  • 到这时以上的六个阶段都已经完成了,接下来处于空闲阶段(Idle Peroid),可以在这时执行 requestIdleCallback 里注册的任务

这样我们把工作单元的任务放到requestIdleCallback回调当中,如果浏览器处理完上述的任务(布局和绘制之后),还有盈余时间,这个时候就可以执行我们的工作单元了。每次执行完一个执行单元。React会去检测还剩多少时间,如果没有时间就将控制权让给浏览器。直至,React和浏览器通过合作式调度完美配合,实现高性能应用。

Fiber执行原理

从根节点开始调度和渲染可以分为两个阶段:rendercommit。 先来了解下这几个关键名词:

workInProgress tree:

workInProgress 代表当前正在执行更新的 Fiber 树。在 setState或者渲染 后,会构建一颗 Fiber 树,也就是 workInProgress tree

currentFiber tree:

首次渲染之后,React 会生成一个对应于 UI 渲染的 fiber 树,称之为 current 树。在新一轮更新时 workInProgress tree 再重新构建,新workInProgress的节点通过 alternate 属性和 currentFiber 的节点建立联系。

Effects list:

effect list 可以理解为是一个存储 effect 副作用列表容器。

render阶段:

render阶段中,会找到所有节点的变更,比如说节点新增,编辑,删除等等。这些变更React称之为副作用effect。在这个阶段中,也可以认为是diff阶段,主要就是对比currentFiber treeworkInProgress tree之间的差异,然后打上标记

在这个阶段,任务是可以终止的。React 可以根据当前可用的时间片处理一个或多个 fiber 节点,并且得益于 fiber 对象中存储的元素上下文信息以及构成的链表结构,使其能够将执行到一半的工作仍保存在内存的链表中。在重新获得控制权后,又可以根据保存在内存中的上下文信息快速找到停止的fiber节点,然后继续工作执行工作单元。

遍历节点过程:

遍历Fiber tree时采用的是后序遍历方法

  • 从顶部开始遍历
  • 如果有child节点,且还未遍历,遍历child节点
  • 如果有child节点,且已经遍历过,则遍历sibling节点。
  • 如果没有child节点,返回父节点
  • 如果最后返回的节点为顶部,表示所有节点遍历完成。

收集effect list:

在遍历的过程中,我们会去收集所有变更的节点产出的effect,每个effect通过链表的方式链接。每个 fiber 有两个属性

  • firstEffect:指向第一个有副作用的子fiber
  • lastEffect:指向最后一个有副作用的子fiber

中间的使用nextEffect做成一个单链表。

commit阶段:

render阶段不同,commit阶段是同步操作的。

为什么commit必须是同步的操作的?

因为在commit阶段是更新真实的dom,所以更新dom不可能一点一点去更新,这样用户体验会极差。所以commit阶段必须是同步执行,一次更新到位。

首先的事情是遍历effect-list列表,拿到每一个 effect 存储的信息,根据副作用类型 effectTag 执行相应的处理并提交更新到真正的 DOM。所有的effects都会在layout phase阶段之前被处理。当该阶段执行结束时,workInProgress树会被替换成current树。到这里,根据收集到的变更信息完成了刷新操作。

以上就是react fiber执行原理示例解析的详细内容,更多关于react fiber执行原理的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

react fiber执行原理示例解析

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

下载Word文档

猜你喜欢

react fiber执行原理示例解析

这篇文章主要为大家介绍了react fiber执行原理示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

react fiber执行原理是什么

本文小编为大家详细介绍“react fiber执行原理是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“react fiber执行原理是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。为什么要使用fiber
2023-07-04

React Fiber 链表操作及原理示例详解

这篇文章主要为大家介绍了React Fiber 链表操作原理详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

React Streaming SSR原理示例深入解析

这篇文章主要为大家介绍了React Streaming SSR原理示例深入解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-12-20

mybatis-plugin插件执行原理解析

这篇文章主要介绍了mybatis-plugin插件执行原理,我们就需要来研究下Executor,ParameterHandler,ResultSetHandler,StatementHandler这4个对象的具体跟sql相关的方法,然后再进行修改,就可以直接起到aop的作用,需要的朋友可以参考下
2022-11-13

onMeasure被执行两次原理解析

这篇文章主要为大家介绍了onMeasure被执行两次原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-02-07

jsjiami.v6解密原理示例分析

这篇文章主要为大家介绍了jsjiami.v6解密原理示例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-16

gosyncOnce实现原理示例解析

这篇文章主要为大家介绍了gosyncOnce实现原理示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-03

OPENMP SECTIONS CONSTRUCT原理示例解析

这篇文章主要为大家介绍了OPENMP SECTIONS CONSTRUCT原理示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-03-06

SparkSQl中运行原理的示例分析

这篇文章将为大家详细讲解有关SparkSQl中运行原理的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一:什么是SparkSQL?(一)SparkSQL简介Spark SQL是Spark的一个模块
2023-06-20

C#使用Task实现执行并行任务的原理的示例详解

Task是一个表示异步操作的类,它提供了一种简单、轻量级的方式来创建多线程应用程序。本文就来和大家聊聊在C#中如何使用Task执行并行任务吧
2023-05-14

Flink on yarn运行原理的示例分析

小编给大家分享一下Flink on yarn运行原理的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!Flink运行时由两种类型的进程组成:1),JobManager也叫master协调分布式执行。他们调度任务,协调
2023-06-19

java LockSupport实现原理示例解析

这篇文章主要为大家介绍了java LockSupport实现原理示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-09

Object.assign触发watch原理示例解析

这篇文章主要为大家介绍了Object.assign触发watch原理示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

Label Propagation算法原理示例解析

这篇文章主要为大家介绍了Label Propagation算法原理示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-02-01

编程热搜

目录