React源码分析(一)Fiber

news2024/11/26 8:35:38

前言

本次React源码参考版本为17.0.3

React架构前世今生

查阅文档了解到, React@16.x是个分水岭。

React@15及之前

在16之前,React架构大致可以分为两层:

  • Reconciler: 主要职责是对比查找更新前后的变化的组件;
  • Renderer: 主要职责是基于变化渲染页面;

但是React团队意识到这样的架构有致命问题: 因为在React15中,组件的更新是基于递归查找实现的,这样一旦开始递归,是没有办法中断的,如果组件层级很深,就会出现性能问题,导致页面卡顿。

React@16及之后

为了解决这样的问题,React团队在React@16进行了重构,引入了新的架构模型:

  • Reconciler: 主要职责是对比查找更新前后的变化的组件;
  • Renderer: 主要职责是基于变化渲染页面;
  • Scheduler: 主要职责是区分任务优先级,优先执行高优先级的任务;

新的架构在原来的基础上引入了Scheduler(调度器),这个东西是React团队参考浏览器的API:requestIdleCallback实现的。它的主要作用就是调度更新任务:

  • 一方面可以中断当前任务执行更高优先级的任务;
  • 另一方面能判断浏览器空闲时间,在恰当的时间将主动权给到浏览器,保证页面性能;并在浏览器下次空闲时继续之前中断的任务; 这样就将之前的不可中断的同步更新变成了异步可中断更新,不直接使用浏览器API可能考虑到兼容问题,可能也有别的方面的考量。
    下面是新的React架构更新模型:

image.png

这个新的架构在进入Renderer之前的流程是可以被中断的,主要有下列两种情况:

  • 进入了更高优先级的任务;
  • 浏览器在当前帧没有剩余空闲时间了;

Fiber

Fiber简单的理解就是React15版本的虚拟DOM。

Fiber简单理解

如果将新的React架构比作一个公司,Fiber在新的架构里承担的就是这个公司的员工,员工也有等级,老板,部长,基层,每个人有自己的职责,知道自己在哪个节点该做什么工作,并将未完成的工作记住等第二天上班继续完成,从而保证公司的顺利运行。而每个Fiber对应一个React element
假如有这样一段代码:

function App() {
    return (
        <div>
            <span>牛牛</span>
            <span>不怕困难</span>
        </div>
     )
}

上面的代码的抽象Fiber树:

image.png 其中的每个方块都是一个Fiber,它们通过child, return, sibling连接对方构成一个Fiber树。

Fiber结构

来看一个Fiber会有哪些属性:

function FiberNode(tag, pendingProps, key, mode) {
  // Instance
  this.tag = tag;   // 组件类型
  this.key = key;   // 组件props上的key
  this.elementType = null;      // ReactElement.type 组件的dom类型, 比如`div, p`
  this.type = null;     // 异步组件resolved之后返回的内容
  this.stateNode = null; // 在浏览器环境对应dom节点

  this.return = null;       // 指向父节点
  this.child = null;        // 孩子节点
  this.sibling = null;      // 兄弟节点, 兄弟节点的return指向同一个父节点

  this.index = 0;
  this.ref = null;          // ref
  this.pendingProps = pendingProps;     // 新的props
  this.memoizedProps = null;        // 上一次渲染完成的props
  this.updateQueue = null;          // 组件产生的update信息会放在这个队列
  this.memoizedState = null;        // // 上一次渲染完成的state
  this.dependencies = null;
  this.mode = mode; // Effects

  this.flags = NoFlags;     // 相当于之前的effectTag, 记录side effect类型
  this.nextEffect = null;   // 单链表结构, 便于快速查找下一个side effect
  this.firstEffect = null;  // fiber中第一个side effect
  this.lastEffect = null;   // fiber中最后一个side effect
  this.lanes = NoLanes;     // 优先级相关
  this.childLanes = NoLanes;  // 优先级相关
  this.alternate = null;    // 对应的是current fiber
}

Fiber工作原理

在弄明白Fiber工作原理之前,我们要先明确一个认知:新的React架构使用了两个Fiber树。

  • 一个Fiber树是当前页面dom的抽象,叫current
  • 另一个Fiber树是在内存中执行更新任务dom的抽象,叫workInProgress

这样做是为了方便比对变化组件,并降低创建的成本,尽可能复用现有代码逻辑,从而提高渲染效率。相关参考视频讲解:进入学习

mount

React代码在第一次执行时,因为页面还没有渲染出来,此时是没有current树的,只有一个正在构建DOM的workInProgress树。

假如我们有这样一段代码:

function App() {
    return (
        <div>
            <span>牛牛</span>
            <span>不怕困难</span>
        </div>
     )
}

ReactDOM.render(<App/>, document.querySelector('#root'));

基于上面的代码在mount会生成这样的Fiber树:

可以看到这个图只是在前面的图上增加了fiberRootrootFiber两个Fiber节点。

  • fiberRoot:整个React应用的根节点;
  • rootFiber: 某个组件树的根节点;(因为我们可能多次使用React.render()函数,这样就会有多个rootFiber)

图中此时fiberRoot对应的rootFiber下面还是空的,因为此时是第一次渲染,页面上没有任何东西,当workInProgress树构建完成,在mutation之后,layout之前,fiberRootd的current指针会指向workInProgress树,把它作为新的current树,此时结构会变成这样:

image.png 这时页面渲染完成了,等待下次触发更新时会从current树进行拷贝生成workInProgress树,然后比对更新。

update

如果我们在上面的代码中触发更新,将牛牛文本改成了勇敢牛牛,React代码就会开始进行任务调度,因为只有这一个任务,会马上执行,会从current树的rootFiber进行拷贝生成workInProgress树的根节点,在经过向下遍历比对,发现相同的就直接从current树上拷贝复用,直到比对到叶子节点的牛牛文本变了,这时才会生成新的Fiber(这里只是为了方便解释,其实我这里使用的代码牛牛不会生成新的Fiber,因为是纯文本,只会替换父级节点的props)

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

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

相关文章

TMS Logging提供了短日志输出

TMS Logging提供了短日志输出 TMS Logging Compact跨平台框架以最小的代码量为各种目标提供了短日志输出。 TMS记录惊人属性&#xff1a; 登录到一个或多个输出处理程序&#xff0c;如控制台、HTML、文本、文本、CSV文件、TCP/IP、浏览器、Windows事件日志等&#xff0c;。。。…

代码质量与安全 | 使用Incredibuild加速Klocwork静态代码分析

Klocwork是一款优秀的静态代码分析和SAST工具&#xff0c;适用于 C、C、C#、Java、JavaScript、Python和Kotlin&#xff0c;可识别软件安全性、质量和可靠性问题&#xff0c;帮助强制遵守标准。 Incredibuild是一款加速编译工具&#xff0c;为C代码编译和分析提供强大的分布式处…

IMX6ULL学习记录——持续更新中......

环境搭建小记 问题集锦 1、nfs无法挂载的问题 原因&#xff1a;ubuntu16之后nfs默认使用nfs的版本为3,4 解决&#xff1a;原子用户手册中/【正点原子】I.MX6U网络环境TFTP&NFS搭建手册V1.3.1/第四章 4.3 NFS挂载文件系统 具体&#xff1a; sudo vim /etc/default/nfs…

CISAW信息安全保障人员认证考试难吗?

CISAW信息安全保障人员认证&#xff0c;作为信息安全行业相当热门的证书之一&#xff0c;其持证人数已超50%&#xff0c;在信息安全行业内占有一席之地&#xff0c;很多报考人都比较关心CISAW考试难不难&#xff1f;能通过吗&#xff1f;那接下来说一说CISAW证书考不好考&#…

《WEB前端框架开发技术》HTML5响应式旅游景区网站设计与实现——榆林子州HTML+CSS+JavaScript

&#x1f468;‍&#x1f393;学生HTML静态网页基础水平制作&#x1f469;‍&#x1f393;&#xff0c;页面排版干净简洁。使用HTMLCSS页面布局设计,web大学生网页设计作业源码&#xff0c;这是一个不错的旅游网页制作&#xff0c;画面精明&#xff0c;排版整洁&#xff0c;内容…

面向OLAP的列式存储DBMS-12-[ClickHouse]的管理与运维

ClickHouse 的管理与运维 ClickHouse 管理和运维相关的知识&#xff0c;该部分可以让 ClickHouse 变得更加安全与健壮。在前面演示的案例中&#xff0c;为了方便&#xff0c;我们一直使用默认的 default 用户&#xff0c;并且没有配置密码&#xff0c;这显然不符合生产环境的要…

怎么看电脑配置?电脑配置好不好?详细教程来了!

小伙伴出去买电脑&#xff0c;最关心的就是电脑配置问题。买回电脑后&#xff0c;首先应该是查看自己的电脑配置&#xff0c;看看是否跟商家宣传的一样&#xff0c;有没有出现被更换的问题。那么怎么看电脑配置呢&#xff1f;怎么看电脑配置和型号&#xff1f;接下来小编就跟大…

算法设计与分析 SCAU19184 传球游戏

19184 传球游戏 时间限制:1000MS 代码长度限制:10KB 提交次数:0 通过次数:0 题型: 编程题 语言: G;GCC;VC;JAVA Description n个同学站成一个圆圈&#xff0c;其中的一个同学手里拿着一个球&#xff0c;每个同学可以把球传给自己左右的两个同学中的一个&#xff08;左右任意…

制作一个简单HTML抗疫逆行者网页作业(HTML+CSS)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

Spring循环依赖

一、循环依赖全景图 二、什么是循环依赖问题&#xff1f; 1、什么是循环依赖&#xff1a; 类与类之间的依赖关系形成了闭环&#xff0c;就会导致循环依赖问题的产生。 比如下图中A类依赖了B类&#xff0c;B类依赖了C类&#xff0c;而最后C类又依赖了A类&#xff0c;这样就形…

免费分享一个springboot+vue学生选课管理系统,挺漂亮的

大家好&#xff0c;我是锋哥&#xff0c;看到一个不错的springbootvue前后端分离的学生选课管理系统&#xff0c;分享下哈。 项目介绍 这是一个采用前后端分离开发的项目&#xff0c;前端采用 Vue 开发、后端采用 SpringBoot Mybatis 开发。 项目部署 1. 将 studentms.sql…

如何将图片在线转换成文字?分享在线转换方法

怎么把图片转换成文字内容呢&#xff1f;大家在日常中使用的图片文件&#xff0c;很多时候都会拿来记录重要内容&#xff0c;如黑板上的文字来不及记下来就要被擦掉&#xff0c;演示的PPT文件没记完就换页了等操作&#xff0c;这就让我们很多小伙伴养成了用图片拍照或截图来记录…

Java案例——控制台实现QuickHit小游戏

一、需求概述 1.根据输入速率和正确率将玩家分为不同级别 2.级别越高&#xff0c;一次显示的字符数越多&#xff0c;玩家正确输入一次的得分也越高 3.规定时间内完成规定次数的输入&#xff0c;正确率达到规定要求&#xff0c;则升级 4.玩家最高级别为6级、初始级别一律为1…

chapter4——时钟分频器

目录同步整数分频器具有50%占空比的奇数整数分频非整数分频&#xff08;非50%占空比&#xff09;典型情况下SOC要对设计中各种组件提供许多与相位相关的时钟。将主时钟以2为幂次进行分割来产生同步偶数分频时钟&#xff0c;有时也会需要按奇数或小数进行分频。 同步整数分频器…

python推导式全局变量多参数传参装饰器

目录 一、推导式运用 二、全局变量 三、多参数传参 四、装饰器 一、推导式运用 # 推导式# for i in range(10): # print(i)# 创建列表 其中奇数位为1&#xff0c; 偶数位为0a[ i for i in range(10)] a2[ 1 if i %2 0 else 0 for i in range(10) ] print(a) print(a2) pr…

LEADTOOLS 入门教程: 使用文档转换器转换文件 - .NET Core

LEADTOOLS是一个综合工具包的集合&#xff0c;用于将识别、文档、医疗、成像和多媒体技术整合到桌面、服务器、平板电脑、网络和移动解决方案中&#xff0c;是一项企业级文档自动化解决方案&#xff0c;有捕捉&#xff0c;OCR&#xff0c;OMR&#xff0c;表单识别和处理&#x…

5款可以在学习和办公上提供帮助的软件

今天给大家推荐5个我自己也常用的软件&#xff0c;可以解决很多问题&#xff0c;给你的学习和办公带来巨大帮助。 1.文档检索启动——Listary 最近一直在整理文档&#xff0c;很多笔记和学案都已经不用了&#xff0c;想着进行一个归档&#xff0c;首先对磁盘进行了分区管理&a…

Spring 简介和基础使用

历史的选择 Spring 作为一个基础的框架&#xff0c;是在 Java EE 开发历史中&#xff0c;是成千上万公司选择。单独使用 Spring 的非常少了&#xff0c;很多都是用 Spring-Boot/Spring-Cloud 来开发&#xff0c;但是 Spring 基础依然是我们使用的基石。我们将一起来聊一聊 Spr…

算法竞赛入门【码蹄集进阶塔335题】(MT2301-2305)

算法竞赛入门【码蹄集进阶塔335题】(MT2301-2305&#xff09; 文章目录算法竞赛入门【码蹄集进阶塔335题】(MT2301-2305&#xff09;前言为什么突然想学算法了&#xff1f;为什么选择码蹄集作为刷题软件&#xff1f;目录1. MT2301 47论2. MT2302 数的增殖3. MT2303 传染病4. MT…

笔试强训2

题目1&#xff1a; 倒置字符串_牛客题霸_牛客网 我们先写出代码&#xff1a; #include<iostream> #include<string> using namespace std; int main() {string s;getline(cin, s);reverse(s.begin(), s.end());auto start s.begin();while (start ! s.end()){au…