当前位置: 首页 > news >正文

React16源码: React中的不同的expirationTime的源码实现

不同的 expirationTime


1 )概述

  • 在React中不仅仅有异步任务
  • 大部分情况下都是同步的任务,所以会有不同 expirationTime 的存在

2 )种类

  • A. Sync 模式,优先级最高
    • 任务创建完成之后,立马更新到真正的dom里面
    • 是一个创建即更新的流程
  • B. Async 模式, 异步模式
    • 会有一个调度
    • 包含一系列复杂的操作在里面
    • 可能会中断,所以会有一个计算出来的过期时间
    • 过期时间根据异步的两种情况,如前文所述
      • 最低优先级的异步
      • 最高优先级的异步
  • C. 指定context

3 ) 源码

  • 在 ReactFiberReconciler.js 中的 updateContainer
    • 调用的是 computeExpirationForFiber
      • 它接收两个参数: currentTime: ExpirationTime, fiber: Fiber
    • 这个方法来自于 ReactFiberScheduler.js 文件
      function computeExpirationForFiber(currentTime: ExpirationTime, fiber: Fiber) {let expirationTime;if (expirationContext !== NoWork) {// An explicit expiration context was set;expirationTime = expirationContext;} else if (isWorking) {if (isCommitting) {// Updates that occur during the commit phase should have sync priority// by default.expirationTime = Sync;} else {// Updates during the render phase should expire at the same time as// the work that is being rendered.expirationTime = nextRenderExpirationTime;}} else {// No explicit expiration context was set, and we're not currently// performing work. Calculate a new expiration time.if (fiber.mode & ConcurrentMode) {if (isBatchingInteractiveUpdates) {// This is an interactive updateexpirationTime = computeInteractiveExpiration(currentTime);} else {// This is an async updateexpirationTime = computeAsyncExpiration(currentTime);}// If we're in the middle of rendering a tree, do not update at the same// expiration time that is already rendering.if (nextRoot !== null && expirationTime === nextRenderExpirationTime) {expirationTime += 1;}} else {// This is a sync updateexpirationTime = Sync;}}if (isBatchingInteractiveUpdates) {// This is an interactive update. Keep track of the lowest pending// interactive expiration time. This allows us to synchronously flush// all interactive updates when needed.if (expirationTime > lowestPriorityPendingInteractiveExpirationTime) {lowestPriorityPendingInteractiveExpirationTime = expirationTime;}}return expirationTime;
      }
      
      • 1 )这里有一系列的判断,首先是对 expirationContext 的判断
        • 它是 ExpirationTime 类型,默认初始化值是 NoWork
        • 下面是它的一个修改场景
          function deferredUpdates<A>(fn: () => A): A {const currentTime = requestCurrentTime();const previousExpirationContext = expirationContext;const previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates;expirationContext = computeAsyncExpiration(currentTime); // 这里isBatchingInteractiveUpdates = false;try {return fn();} finally {expirationContext = previousExpirationContext;isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates;}
          }
          
          • expirationContext = computeAsyncExpiration(currentTime);
          • 可以看到 computeAsyncExpiration 这个函数对其进行修改赋值
        • 还有一种场景, 往下进行搜索
          function syncUpdates<A, B, C0, D, R>(fn: (A, B, C0, D) => R,a: A,b: B,c: C0,d: D,
          ): R {const previousExpirationContext = expirationContext;expirationContext = Sync; // 变成了 Synctry {return fn(a, b, c, d); // 这里是 setState 操作} finally {expirationContext = previousExpirationContext; // 最终还原}
          }
          
          • syncUpdates 在 ReactDOM.js 中的 flushSync API
            • flushSync: DOMRenderer.flushSync 一直溯源往上找到 ReactFiberScheduler.js 中的 flushSync
            • 这个就是 本源的 flushSync
              // TODO: Batching should be implemented at the renderer level, not within
              // the reconciler.
              function flushSync<A, R>(fn: (a: A) => R, a: A): R {invariant(!isRendering,'flushSync was called from inside a lifecycle method. It cannot be ' +'called when React is already rendering.',);const previousIsBatchingUpdates = isBatchingUpdates;isBatchingUpdates = true;try {return syncUpdates(fn, a); // 这里} finally {isBatchingUpdates = previousIsBatchingUpdates;performSyncWork();}
              }
              
            • 上述调用的是 syncUpdates,在之前的示例中,如下
              flushSync(() => {this.setState({num: newNum,})
              })
              
            • 上述示例就是传入 fn 回调, 内部调用 setState
            • 在这种场景下 expirationTime 变成了 Sync
        • 以上两种情况 是给 expirationContext 进行赋值
      • 2 )当 expirationTime 变成了 Sync 就不符合第一种情况了,这时候往下走,匹配到了 isWorking
        • isWorking 表示有任务正在更新
        • 也是基于条件指定某个值
        • 这块涉及到后续任务的更新,跳过
      • 3 )没有外部强制的情况下
        • if (fiber.mode & ConcurrentMode)
        • 判断 fiber.mode 是否是 ConcurrentMode
        • 找到 ConcurrentMode 的定义处 ReactTypeOfMode.js
          export type TypeOfMode = number;export const NoContext = 0b000;
          export const ConcurrentMode = 0b001;
          export const StrictMode = 0b010;
          export const ProfileMode = 0b100;
          
        • 可见,使用二进制方式来定义的
        • 可以通过 与或 这类逻辑的操作,非常方便的组合 Mode
        • 以及判断是否有某个Mode,例如
          const a = 0b000;
          const b = 0b001;
          const c = 0b010;
          const d = 0b100;
          let mode = a; // 默认等于 a, 在后续渲染时并不知道是否有更改过
          mode & b // 如果 结果为 0 表示没有过b这种情况
          mode |= b // 这样给 mode 增加 b,这时候 mode 变成1,就对应了 b
          mode |= c // 给 mode 增加 c, 这时候 mode 变成 3,也就是 0b011
          mode & b // 这时候判断mode是否有b, 如果是1,则有b, 结果是1 对应b
          mode & c // 这时候判断mode是否有c, 如果是1,则有c, 结果是2 对应c
          
          • 这是一种巧妙的设计方式
          • 类似的,在 ReactSideEffectTags.js 中也是这么设计的
        • 回到代码里,如果是 ConcurrentMode 才会调用
        • computeInteractiveExpirationcomputeAsyncExpiration 两个函数中的一个计算 expirationTime
          if (isBatchingInteractiveUpdates) {// This is an interactive updateexpirationTime = computeInteractiveExpiration(currentTime);
          } else {// This is an async updateexpirationTime = computeAsyncExpiration(currentTime);
          }
          
          • 关于 isBatchingInteractiveUpdatesinteractiveUpdates 函数中被赋值为 true
            • 大部分的 React 事件产生的更新,事件中绑定回调函数,这个回调函数执行的时候
            • 大部分都是在 interactiveUpdates 情况下,也就是 isBatchingInteractiveUpdates 为 true 时
          • 后面 expirationTime += 1; 是为了区分下一个即将进行的更新和当前正在创造的更新,防止一样,强制把当前+1
        • 如果不属于,则还是 Sync

相关文章:

React16源码: React中的不同的expirationTime的源码实现

不同的 expirationTime 1 &#xff09;概述 在React中不仅仅有异步任务大部分情况下都是同步的任务&#xff0c;所以会有不同 expirationTime 的存在 2 &#xff09;种类 A. Sync 模式&#xff0c;优先级最高 任务创建完成之后&#xff0c;立马更新到真正的dom里面是一个创建…...

TRB 2024论文分享:基于生成对抗网络和Transformer模型的交通事件检测混合模型

TRB&#xff08;Transportation Research Board&#xff0c;美国交通研究委员会&#xff0c;简称TRB&#xff09;会议是交通研究领域知名度最高学术会议之一&#xff0c;近年来的参会人数已经超过了2万名&#xff0c;是参与人数和国家最多的学术盛会。TRB会议几乎涵盖了交通领域…...

Golang 打包

构建/打包 使用 Go 的构建命令&#xff1a; go build在包含 main 函数的包的目录下执行&#xff0c;它会生成一个可执行文件。文件名默认与包所在的目录名相同&#xff0c;但也可以使用 -o 选项来指定输出的文件名 交叉编译 Windows 环境下进行交叉编译以构建其他平台的可执…...

力扣每日一练(24-1-14)

做过类似的题&#xff0c;一眼就是双指针&#xff0c;刚好也就是题解。 if not nums:return 0p1 0 for p2 in range(1, len(nums)):if nums[p2] ! nums[p1]:p1 1nums[p1] nums[p2]return p1 1 根据规律&#xff0c;重复的数字必定相连&#xff0c;那么只要下一个数字与上一…...

K 个一组翻转链表(链表反转,固定长度反转)(困难)

优质博文&#xff1a;IT-BLOG-CN 一、题目 给你链表的头节点head&#xff0c;每k个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是k的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。…...

Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级

文章目录 Resilience4j概述Resilience4j官方地址Resilience4j-RateLimiter微服务演示Payment processorPOM配置文件ServiceController Payment servicePOMModelServiceRestConfigController配置验证 探究 Rate Limiting请求三次 &#xff0c;观察等待15秒连续访问6次 Resilienc…...

概率论与数理统计————1.随机事件与概率

一、随机事件 随机试验&#xff1a;满足三个特点 &#xff08;1&#xff09;可重复性&#xff1a;可在相同的条件下重复进行 &#xff08;2&#xff09;可预知性&#xff1a;每次试验的可能不止一个&#xff0c;事先知道试验的所有可能结果 &#xff08;3&#xff09;不确定…...

【生存技能】git操作

先下载git https://git-scm.com/downloads 我这里是win64&#xff0c;下载了相应的直接安装版本 64-bit Git for Windows Setup 打开git bash 设置用户名和邮箱 查看设置的配置信息 获取本地仓库 在git bash或powershell执行git init&#xff0c;初始化当前目录成为git仓库…...

docker 将镜像打包为 tar 包

目录 1 实现 1 实现 要将镜像导出为.tar包&#xff0c;可以使用Docker命令行工具进行操作。下面是导出镜像的步骤&#xff1a; 首先&#xff0c;使用以下命令列出当前系统上的镜像&#xff0c;并找到要导出的镜像的ID或名称&#xff1a; docker images使用以下命令将镜像导出为…...

341. 最优贸易(dp思想运用,spfa,最短路)

341. 最优贸易 - AcWing题库 C 国有 n 个大城市和 m 条道路&#xff0c;每条道路连接这 n 个城市中的某两个城市。 任意两个城市之间最多只有一条道路直接相连。 这 m 条道路中有一部分为单向通行的道路&#xff0c;一部分为双向通行的道路&#xff0c;双向通行的道路在统计…...

FineBI实战项目一(19):每小时订单笔数分析开发

点击新建组件&#xff0c;创建下每小时订单笔数组件。 选择饼图&#xff0c;拖拽cnt&#xff08;总数&#xff09;到角度&#xff0c;拖拽hourstr到颜色&#xff0c;调节内径。 修改现在的文字 拖拽组件到仪表盘。 效果如下&#xff1a;...

What is `@RequestBody ` does?

RequestBody 是SpringMVC框架中的注解&#xff0c;通常与POST、PUT等方法配合使用。当客户端发送包含JSON或XML格式数据的请求时&#xff0c;可以通过该注解将请求体内容绑定到Controller方法参数上 作用 自动反序列化&#xff1a; SpringMVC会根据RequestBody注解的参数类型&…...

Windows安装Rust环境(详细教程)

一、 安装mingw64(C语言环境) Rust默认使用的C语言依赖Visual Studio&#xff0c;但该工具占用空间大安装也较为麻烦&#xff0c;可以选用轻便的mingw64包。 1.1 安装地址 (1) 下载地址1-GitHub&#xff1a;Releases niXman/mingw-builds-binaries GitHub (2) 下载地址2-W…...

Marin说PCB之传输线损耗---趋肤效应和导体损耗01

大家在做RF上的PCB走线或者是车载相机的上走线的时候经常会听那些硬件工程师们说你这个走线一定要保证50欧姆的阻抗匹配啊&#xff0c;还有就是记得加粗走做隔层参考。 有的公司的EE硬件同事会很贴心的把RF走线的注意事项给你备注在原理图上或者是layoutguide上&#xff0c;遇到…...

八:分布式锁

1、为什么要使用分布式锁 锁是多线程代码中的概念&#xff0c;只有多任务访问同一个互斥的共享资源时才需要锁。单机应用开发时一般使用synchronized或lock。多线程的运行都是在同一个JVM之下。应用是分布式集群&#xff0c;属于多JVM的工作环境&#xff0c;JVM之间已经无法通过…...

示例:php将文本内容写入一个文件(面向过程写法)

一、封装2个函数&#xff0c;读写文件 /*** desc 读取文件内容* param string $filename* return array*/ private function readContent(string $filename): array {$text file_get_contents($filename);if (!$text) {return [];}$result json_decode($text,true);return…...

Flutter开发进阶之并发操作数据库

Flutter开发进阶之并发操作数据库 尽管 Flutter 本身不包含任何数据库功能&#xff0c;但可以使用各种第三方库和插件来在 Flutter 应用程序中实现数据库功能&#xff1b; 以下将使用sqflite作为例子&#xff0c;sqflite允许在 Flutter 应用程序中执行 SQL 查询&#xff0c;创…...

docker应用:搭建uptime-kuma监控站点

简介&#xff1a;Uptime Kuma是一个易于使用的自托管监控工具&#xff0c;它的界面干净简洁&#xff0c;部署和使用都非常方便。 历史攻略&#xff1a; docker&#xff1a;可视化工具portainer docker-compose&#xff1a;搭建自动化运维平台Spug 开源地址&#xff1a; ht…...

在illustrator中按大小尺寸选择物体 <脚本 018>

在Illustrator中我们可以依据对象的属性 如&#xff1a;填充颜色、描边颜色或描边宽度来选择相同属性的对象&#xff0c;但是Illustrator中没有根据不同大小尺寸来选择对象的功能&#xff0c;下面介绍的就是根据大小尺寸选择对象的脚本。 1、下面是当前画板中的所有对象&#…...

leetcode - 934. Shortest Bridge

Description You are given an n x n binary matrix grid where 1 represents land and 0 represents water. An island is a 4-directionally connected group of 1’s not connected to any other 1’s. There are exactly two islands in grid. You may change 0’s to 1…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

BLEU评分:机器翻译质量评估的黄金标准

BLEU评分&#xff1a;机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域&#xff0c;衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标&#xff0c;自2002年由IBM的Kishore Papineni等人提出以来&#xff0c;…...

全面解析数据库:从基础概念到前沿应用​

在数字化时代&#xff0c;数据已成为企业和社会发展的核心资产&#xff0c;而数据库作为存储、管理和处理数据的关键工具&#xff0c;在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理&#xff0c;到社交网络的用户数据存储&#xff0c;再到金融行业的交易记录处理&a…...