React16源码: React中FiberRoot的源码实现

SpringBoot项目里用poi-tl 1.12.0导出Word,遇到NoClassDefFoundError怎么办? 本文详细解析了SpringBoot项目中使用poi-tl 1.12.0导出Word时遇到的NoClassDefFoundError报错问题,提供了依赖冲突排查指南和多种解决方案,包括排除冲突依赖、统一版本管理和使用dependencyManagement等,帮助开发者快速解决类似问题。 阅读详情

关于 FiberRoot


1 )概述

  • 在 ReactDOM.render 过程当中,创建了一个 ReactRoot的对象
  • 这个 ReactRoot 对象最主要承担了创建 FiberRoot 对象
  • 这个对象它非常重要,在后期整个应用调度过程当中都会跟它有关
  • 关于 FiberRoot 对象
    • A. 它是整个应用的起点
    • B. 它包含了ReactDOM.render 传进去的第二个参数
      • 就是一个dom节点,我们应用挂载的那个节点相关的一些信息
    • C. 它还记录着整个应用更新过程当中的各种信息
      • 应用更新过程当中,会涉及到各种各样的东西
    • 比如,各种不同类型的 expirationTime,还有异步调度任务的callback这些东
    • 都会记录在这个 FiberRoot 上面

2 ) 相关源码

  • 在 ReactRoot 构造函数中基于 DOMRenderer.createContainer 创建了 FiberRoot 对象
    // ReactDOM.js
    function ReactRoot(
      container: Container,
      isConcurrent: boolean,
      hydrate: boolean,
    ) {
      const root = DOMRenderer.createContainer(container, isConcurrent, hydrate);
      this._internalRoot = root;
    }
    
    // ReactFiberReconciler.js
    export function createContainer(
      containerInfo: Container,
      isConcurrent: boolean,
      hydrate: boolean,
    ): OpaqueRoot {
      return createFiberRoot(containerInfo, isConcurrent, hydrate);
    }
    
    // ReactFiberRoot.js
    export function createFiberRoot(
      containerInfo: any,
      isConcurrent: boolean,
      hydrate: boolean,
    ): FiberRoot {
      // Cyclic construction. This cheats the type system right now because
      // stateNode is any.
      const uninitializedFiber = createHostRootFiber(isConcurrent);
    
      let root;
      if (enableSchedulerTracing) {
        root = ({
          // root 节点对应的Fiber对象(root节点也是可能会更新的),是 Root Fiber
          // 后续整个应用都会有一个Fiber的树结构,任何一个ReactElement的节点都会对应一个Fiber对象
          // ReactElement是一个树结构, Fiber对象也会有一个树结构
          // 它是Fiber树结构的顶点
          current: uninitializedFiber,
          containerInfo: containerInfo, // ReactDOM.render 传进去的第二个参数 dom 节点
          pendingChildren: null, // 只有在持久更新中会用到,也就是不支持增量更新的平台,react-dom中不会被用到,在server-render中会被用到,因为它需要输出很多字符串类型的html节点
    
          // 以下的优先级是用来区分
          // 1 ) 没有提交(committed)的任务
          // 2 ) 没有提交的挂起任务
          // 3 ) 没有提交的可能被挂起的任务
    
          // 最老和最新的不确定是否会挂起的优先级 (所有任务进来一开始都是这个状态)
          earliestPendingTime: NoWork,
          latestPendingTime: NoWork,
          // 最老和最新的在提交的时候被挂起的任务
          earliestSuspendedTime: NoWork,
          latestSuspendedTime: NoWork,
          // 最新的通过一个promise被resolve并且可以重新尝试的优先级
          latestPingedTime: NoWork,
    
          didError: false, // 在renderRoot 出现无法处理的错误时会被设置为 true
    
          pendingCommitExpirationTime: NoWork, // 正在等待提交的任务的 expirationTime
          // 已经完成的任务的FiberRoot对象,如果你只有一个Root, 它永远只可能是这个Root对应的Fiber, 或者是 null
          // 在 commit 阶段只会处理这个值对应的任务
          // 用于记录在一次更新渲染过程当中完成了的更新任务, 因为整棵树中会存在各种不同的更新任务
          // 每一次更新会渲染优先级最高的任务,优先级最高的任务渲染完成之后就是一个 finishedWork,标记在应用的Root上面
          // 更新完了要把应用输出到Dom节点上面,输出的过程就是读取的这个 finishedWork 值
          finishedWork: null,
          // 在任务被挂起的时候通过setTimeout设置的返回内容
          // 用来下一次如果有新的任务挂起时清理还没触发的timeout
          // 例如:Suspense 组件功能, 在render function 中 throw 一个 Promise, 之后任务会被挂起
          // 挂起之后可以渲染 Suspense 组件的 fallback, 等到 Promise resolve之后
          // 它就会把 resolve之后的数据显示出来,这时候就会有一个 timeoutHandle来帮助我们记录超时的情况的
          // 这个会在后续的更新流程中
          timeoutHandle: noTimeout,
          // 顶层 context 对象, 只有主动调用 `renderSubtreeIntoContainer` 时才会有用
          // `renderSubtreeIntoContainer` 这个API出场率非常低,不常用
          context: null,
          pendingContext: null,
          // 用来确定第一次渲染的时候是否需要融合
          // 应用是否要跟原来存在的dom节点进行合并
          hydrate,
          // 当前root上剩余的过期时间
          // 用来标记这一次更新渲染的时候要执行的是哪个优先级的任务
          // 应用更新过程中会遍历到每一个节点,每个节点如果有更新,会有自己的一个 ExpirationTime
          // root 上记录整个应用当中优先级最高的 ExpirationTime 
          // 在更新的过程中,会根据这个nextExpirationTimeToWorkOn变量去进行一个更新
          // 就是说如果遍历到某个节点,发现自己的 ExpirationTime 比这个值要大,则说明它优先级要低
          // 且还轮不到它来更新,就可以进行一个跳过,这就是这个变量的用处
          nextExpirationTimeToWorkOn: NoWork,
          // 当前更新对应的过期时间
          // 用在我们调度的过程当中, 和 上面的 nextExpirationTimeToWorkOn 大部分时间都是相同的
          // 但是也会有一定的区别
          expirationTime: NoWork,
          // 暂时不管这个
          firstBatch: null,
          // root之间关联的链表结构
          // 这个属性是单向链表的属性
          // 比如,dom节点有 root1 和 root2 两个div
          // ReactDOM.render 把一个应用渲染在 root1 中,把另一个应用渲染在 root2 中
          // 这时候会存在两个root, 它们在react中会用 nextScheduledRoot 这个属性进行一个串联
          // 在整个react更新调度过程中,在这个链表中去找哪个root对应的优先级最高,执行那个root的更新
          // 一个root里面又会有不同优先级的任务在里面,它整体的过程是非常的复杂
          nextScheduledRoot: null,
    
          interactionThreadID: unstable_getThreadID(),
          memoizedInteractions: new Set(),
          pendingInteractionMap: new Map(),
        }: FiberRoot);
      } else {
        root = ({
          current: uninitializedFiber,
          containerInfo: containerInfo,
          pendingChildren: null,
    
          earliestPendingTime: NoWork,
          latestPendingTime: NoWork,
          earliestSuspendedTime: NoWork,
          latestSuspendedTime: NoWork,
          latestPingedTime: NoWork,
    
          didError: false,
    
          pendingCommitExpirationTime: NoWork,
          finishedWork: null,
          timeoutHandle: noTimeout,
          context: null,
          pendingContext: null,
          hydrate,
          nextExpirationTimeToWorkOn: NoWork,
          expirationTime: NoWork,
          firstBatch: null,
          nextScheduledRoot: null,
        }: BaseFiberRootProperties);
      }
    
      uninitializedFiber.stateNode = root;
    
      // The reason for the way the Flow types are structured in this file,
      // Is to avoid needing :any casts everywhere interaction tracing fields are used.
      // Unfortunately that requires an :any cast for non-interaction tracing capable builds.
      // $FlowFixMe Remove this :any cast and replace it with something better.
      return ((root: any): FiberRoot);
    }
    

3 )相关解析

  • 注意,上面的各种 Time 非常重要,在后续任务调度的过程中,用来记录更新所涉及的时间的
    • js 在浏览器中是单线程的, 我们的应用又是一个树形结构
    • 如何去区分不同优先级的任务,就要用各种不同的变量去标记
    • 这几个变量就是用于去标识不同优先级的任务的
  • 其他字段参考上述源码中注释的释义
UE4免费资产库新玩法:Quixel Bridge插件安装与Megascans资源导入全攻略 本文详细介绍了如何在UE4中安装Quixel Bridge插件并导入Megascans资源,帮助开发者快速获取高质量3D资产。通过分步教程和实用技巧,提升游戏或影视场景的制作效率,特别适合需要真实感环境的项目。 阅读详情

相关推荐

WRF模式学习入门基础(建议收藏!!!)

本文详细介绍了WRF-ARW(Advanced Research WRF)模式的结构组成,重点讲解了前处理系统(WPS)和主模式中的各个关键程序的功能与流程。通过对geogrid、ungrib、metgrid、real和wrf等模块的逐步解析,帮助初学者全面理解数值天气预报模型在初始化和运行过程中所需的关键步骤。

2503_90234341的博客 3077

React 源码讲解第 3 节- FiberRoot 对象

React 源码讲解第 3 节- FiberRoot 对象

杏子 853

嵌入式开发面试题全解析:指针、内存、数据类型关键问题总结

本文对嵌入式开发典型面试题进行深度解析,涵盖多方面关键知识。题目 19 揭示字符指针修改字符串常量的错误操作;题目 20 展现strcpy引发的缓冲区溢出风险;题目 21 体现未初始化数组与strlen结合的不可预测性;题目 22 通过位域与对齐规则计算结构体大小;题目 23 因unsigned char溢出导致循环异常。这些题目全面覆盖指针操作、内存管理、数据类型特性等核心内容,精准指出开发中易疏忽的陷阱,有助于理解编程规范,规避风险,提升代码质量与稳定性,是深入掌握嵌入式开发要点的实用指南。

嵌入式中手 1364

React19源码系列之FiberRoot节点和Fiber节点

fiberRoot节点和fiber节点结构

YanHSama的博客 969

瑞芯微RK3576上手实测:8nm新U配6TOPS NPU,做AIoT项目选它还是RK3588/RK3568?

本文深度评测瑞芯微RK3576芯片在中高端AIoT项目中的表现,对比RK3588和RK3568的性能差异。RK3576采用8nm工艺,配备6TOPS NPU,在解码能力、AI推理效率和功耗控制方面表现均衡,是中端项目的黄金选择。实测数据显示其在多路视频解码和AI加速性能上优势明显,特别适合智能摄像头和工业HMI设备。

weixin_42627853的博客 717

从波形图到参数调优:一次无感BLDC电机启动失败的深度解析

本文深入解析无感BLDC电机启动失败案例,通过波形分析揭示参数不匹配和IPM保护机制触发等关键问题。详细探讨了过零点检测、PWM周期设置及强拖参数调优的底层逻辑,并分享IPM模块保护机制与实战调优技巧,最终实现99.98%的启动成功率。

weixin_29182481的博客 821

React16源码: React中Fiber对象的源码实现

在`FiberRoot`里面,它也会为我们去创建的一个对象叫做 `Fiber`, 在 React16 之后, 非常核心,非常重要的一个东西

Wang的专栏 1526

大厂面经:京东大数据面试题及参考答案(3万字长文)

Kafka是一个开源的分布式流处理平台,由 LinkedIn 开发并在 2011 年贡献给 Apache 软件基金会。高吞吐量:能够处理大量的数据流,适合实时数据管道。持久性:数据存储在磁盘上,确保数据不丢失。容错性:通过数据复制提供高可用性。扩展性:支持水平扩展,易于增加更多节点。Kafka 的核心概念Topic:逻辑上的数据流,可以理解为主题。Producer:生产数据的应用程序。Consumer:消费数据的应用程序。Broker:Kafka 集群中的服务器节点。Partition。

大模型大数据攻城狮的专栏 863

React的一些相关基础概念回顾

react 16版本的架构可以分为三层: 调度层,协调层,渲染层。

前端高薪进击手记 680

开发具有情感分析能力的AI Agent

本文将深入探讨开发具有情感分析能力的AI Agent的各个方面。我们将首先介绍情感分析的基础知识,包括定义、背景和应用领域。接着,我们将详细讲解情感分析的核心概念、数据处理方法和算法原理。随后,文章将展示如何设计情感分析系统架构,并进行项目实战,包括环境安装、源代码实现和案例分析。最后,我们将总结最佳实践和注意事项,为读者提供进一步学习的资源。情感分析(Sentiment Analysis),也称为意见挖掘,是自然语言处理(NLP)的一个分支。

SuperAGI2025 1146

图解联合概率密度、边缘概率密度、条件概率密度之间的关系

简要图解联合概率密度、边缘概率密度、条件概率密度之间的关系

一个搬运知识的笨小孩 2万+

React16源码: React中调度之scheduleWork的源码实现

定位到 packages/react-reconciler/src/ReactFiberScheduler.js。拿之前的一个 Fiber Tree 节点来举例。当中,它需要去找到更新对应的。如果符合条件需要重置 stack。如果符合条件就去请求工作调度。这几个方法最终都调用了。

Wang的专栏 1525

Ultralytics 框架中 model.predict() 返回的 results 对象的详细解析

通过掌握 results 对象的使用方法,您可以快速实现模型部署、数据分析与可视化。

浩瀚之水的专栏 749

react解析: render的FiberRoot(三)

react解析: render的FiberRoot(三) 感谢yck: 剖析 React 源码解析,本篇文章是在读完他的文章的基础上,将他的文章进行拆解和加工,加入我自己的一下理解和例子,便于大家理解。觉得yck写的真的很棒 。React 版本为 16.8.6,关于源码的阅读,可以移步到yck react源码解析 本文永久有效链接:react解析 render的FiberRoo...

weixin_30376163的博客 308

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

React16源码解读:揭秘ReactDOM

怎么样,到目前为止,其实还是觉得挺简单的吧?@param callback ReactDOM.render()或者ReactDOM.hydrate()中的第三个参数,组件渲染完成后需要执行的回调函数。@param container ReactDOM.render()或者ReactDOM.hydrate()中的第二个参数,组件需要挂载的DOM容器。@param container ReactDOM.render()或者ReactDOM.hydrate()中的第二个参数,组件需要挂载的DOM容器。

2401_87029792的博客 1046

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

React16源码: React中调度之requestWork的源码实现

在 scheduleWork 中,找到了创建更新的fiber对应的root节点, 然后对它进行了一些操作之后,调用了 `requestWork`,开始请求工作, 在 requestWork 里面它会做哪些东西呢?首先我们要把这个root节点加入到调度队列当中, 然后判断是否是批量更新, 最后再根据 expirationTime 的类型来判断调度的类型

Wang的专栏 1144

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

React16源码解读:揭秘ReactDOM,前端开发移动

然后我们将代码定位到第632行,可以看到ReactDOM对象包含了很多我们可能使用过的方法,例如renderhydrate和等。本文中我们暂且只关心render方法,但为了方便对比,也可以简单看下hydrate方法:/**服务端渲染@param element 表示一个ReactNode,可以是一个ReactElement对象@param container 需要将组件挂载到页面中的DOM容器@param callback 渲染完成后需要执行的回调函数*/invariant(

2401_84094725的博客 884

React16源码解读:揭秘ReactDOM,前端开发技术调研

前端资料汇总开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】框架原理真的深入某一部分具体的代码和实现方式时,要多注意到细节,不要只能写出一个框架。算法方面很薄弱的,最好多刷一刷,不然影响你的工资和成功率😯在投递简历之前,最好通过各种渠道找到公司内部的人,先提前了解业务,也可以帮助后期优秀 offer 的决策。

m0_60721860的博客 1117

React16源码: React中创建更新的方式及ReactDOM.render的源码实现

在过程当中,创建了一个ReactRoot同时在ReactRoot创建的过程中创建了FiberRoot在创建的过程中也会自动去初始化一个 Fiber 对象(上面暂没有涉及)然后又在这个 root 上面去创建了一个之后又创建了一个 update 这个更新的对象,然后把这个更新的对象放到我们的 root 的节点上面之后就进入了一个更新的过程, 这就是一个创建更新的过程创建完更新, 再去实际的调度整个任务的更新。

Wang的专栏 1595

React16源码解读:揭秘ReactDOM.render

点击上方"前端之境",选择"置顶或者星标"你的关注意义重大!在上一篇文章中我们通过create-react-app脚手架快速搭建了一个简单的示例,并基于该...

frontend_frank的博客 261

React16源码: React中commit阶段的commitAllLifeCycles的源码实现

以上是对所有的具有 SideEffect 的节点在commit过程当中执行任务的一个过程,到这里,整个dom树其实也已经渲染上去了。包括可能存在 autofocus 的处理过程,所以它相当于是在整个应用渲染完成之后的一个善后工作。其实主要是调用不同组件的一个生命周期,以及对于 HostComponent,等组件的不同处理。具体细节,写在上述代码的注释中。

Wang的专栏 1442
上一篇: React16源码: React中创建更新的方式及ReactDOM.render的源码实现
下一篇: React16源码: React中Fiber对象的源码实现
Wang's Blog
博客等级 码龄12年 7433粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值