当前位置: 首页 > 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…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

4. TypeScript 类型推断与类型组合

一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式&#xff0c;自动确定它们的类型。 这一特性减少了显式类型注解的需要&#xff0c;在保持类型安全的同时简化了代码。通过分析上下文和初始值&#xff0c;TypeSc…...

uniapp 小程序 学习(一)

利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 &#xff1a;开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置&#xff0c;将微信开发者工具放入到Hbuilder中&#xff0c; 打开后出现 如下 bug 解…...

在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7

在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤&#xff1a; 第一步&#xff1a; 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为&#xff1a; // 改为 v…...