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 中的flushSyncAPIflushSync: 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就不符合第一种情况了,这时候往下走,匹配到了isWorkingisWorking表示有任务正在更新- 也是基于条件指定某个值
- 这块涉及到后续任务的更新,跳过
- 3 )没有外部强制的情况下
if (fiber.mode & ConcurrentMode)- 判断
fiber.mode是否是ConcurrentMode - 找到
ConcurrentMode的定义处 ReactTypeOfMode.jsexport 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 才会调用
computeInteractiveExpiration和computeAsyncExpiration两个函数中的一个计算expirationTimeif (isBatchingInteractiveUpdates) {// This is an interactive updateexpirationTime = computeInteractiveExpiration(currentTime); } else {// This is an async updateexpirationTime = computeAsyncExpiration(currentTime); }- 关于
isBatchingInteractiveUpdates在interactiveUpdates函数中被赋值为 true- 大部分的 React 事件产生的更新,事件中绑定回调函数,这个回调函数执行的时候
- 大部分都是在
interactiveUpdates情况下,也就是isBatchingInteractiveUpdates为 true 时
- 后面
expirationTime += 1;是为了区分下一个即将进行的更新和当前正在创造的更新,防止一样,强制把当前+1
- 关于
- 如果不属于,则还是
Sync
- 1 )这里有一系列的判断,首先是对
- 调用的是
相关文章:
React16源码: React中的不同的expirationTime的源码实现
不同的 expirationTime 1 )概述 在React中不仅仅有异步任务大部分情况下都是同步的任务,所以会有不同 expirationTime 的存在 2 )种类 A. Sync 模式,优先级最高 任务创建完成之后,立马更新到真正的dom里面是一个创建…...
TRB 2024论文分享:基于生成对抗网络和Transformer模型的交通事件检测混合模型
TRB(Transportation Research Board,美国交通研究委员会,简称TRB)会议是交通研究领域知名度最高学术会议之一,近年来的参会人数已经超过了2万名,是参与人数和国家最多的学术盛会。TRB会议几乎涵盖了交通领域…...
Golang 打包
构建/打包 使用 Go 的构建命令: go build在包含 main 函数的包的目录下执行,它会生成一个可执行文件。文件名默认与包所在的目录名相同,但也可以使用 -o 选项来指定输出的文件名 交叉编译 Windows 环境下进行交叉编译以构建其他平台的可执…...
力扣每日一练(24-1-14)
做过类似的题,一眼就是双指针,刚好也就是题解。 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 根据规律,重复的数字必定相连,那么只要下一个数字与上一…...
K 个一组翻转链表(链表反转,固定长度反转)(困难)
优质博文:IT-BLOG-CN 一、题目 给你链表的头节点head,每k个节点一组进行翻转,请你返回修改后的链表。 k是一个正整数,它的值小于或等于链表的长度。如果节点总数不是k的整数倍,那么请将最后剩余的节点保持原有顺序。…...
Spring Boot - 利用Resilience4j-RateLimiter进行流量控制和服务降级
文章目录 Resilience4j概述Resilience4j官方地址Resilience4j-RateLimiter微服务演示Payment processorPOM配置文件ServiceController Payment servicePOMModelServiceRestConfigController配置验证 探究 Rate Limiting请求三次 ,观察等待15秒连续访问6次 Resilienc…...
概率论与数理统计————1.随机事件与概率
一、随机事件 随机试验:满足三个特点 (1)可重复性:可在相同的条件下重复进行 (2)可预知性:每次试验的可能不止一个,事先知道试验的所有可能结果 (3)不确定…...
【生存技能】git操作
先下载git https://git-scm.com/downloads 我这里是win64,下载了相应的直接安装版本 64-bit Git for Windows Setup 打开git bash 设置用户名和邮箱 查看设置的配置信息 获取本地仓库 在git bash或powershell执行git init,初始化当前目录成为git仓库…...
docker 将镜像打包为 tar 包
目录 1 实现 1 实现 要将镜像导出为.tar包,可以使用Docker命令行工具进行操作。下面是导出镜像的步骤: 首先,使用以下命令列出当前系统上的镜像,并找到要导出的镜像的ID或名称: docker images使用以下命令将镜像导出为…...
341. 最优贸易(dp思想运用,spfa,最短路)
341. 最优贸易 - AcWing题库 C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市。 任意两个城市之间最多只有一条道路直接相连。 这 m 条道路中有一部分为单向通行的道路,一部分为双向通行的道路,双向通行的道路在统计…...
FineBI实战项目一(19):每小时订单笔数分析开发
点击新建组件,创建下每小时订单笔数组件。 选择饼图,拖拽cnt(总数)到角度,拖拽hourstr到颜色,调节内径。 修改现在的文字 拖拽组件到仪表盘。 效果如下:...
What is `@RequestBody ` does?
RequestBody 是SpringMVC框架中的注解,通常与POST、PUT等方法配合使用。当客户端发送包含JSON或XML格式数据的请求时,可以通过该注解将请求体内容绑定到Controller方法参数上 作用 自动反序列化: SpringMVC会根据RequestBody注解的参数类型&…...
Windows安装Rust环境(详细教程)
一、 安装mingw64(C语言环境) Rust默认使用的C语言依赖Visual Studio,但该工具占用空间大安装也较为麻烦,可以选用轻便的mingw64包。 1.1 安装地址 (1) 下载地址1-GitHub:Releases niXman/mingw-builds-binaries GitHub (2) 下载地址2-W…...
Marin说PCB之传输线损耗---趋肤效应和导体损耗01
大家在做RF上的PCB走线或者是车载相机的上走线的时候经常会听那些硬件工程师们说你这个走线一定要保证50欧姆的阻抗匹配啊,还有就是记得加粗走做隔层参考。 有的公司的EE硬件同事会很贴心的把RF走线的注意事项给你备注在原理图上或者是layoutguide上,遇到…...
八:分布式锁
1、为什么要使用分布式锁 锁是多线程代码中的概念,只有多任务访问同一个互斥的共享资源时才需要锁。单机应用开发时一般使用synchronized或lock。多线程的运行都是在同一个JVM之下。应用是分布式集群,属于多JVM的工作环境,JVM之间已经无法通过…...
示例:php将文本内容写入一个文件(面向过程写法)
一、封装2个函数,读写文件 /*** 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 本身不包含任何数据库功能,但可以使用各种第三方库和插件来在 Flutter 应用程序中实现数据库功能; 以下将使用sqflite作为例子,sqflite允许在 Flutter 应用程序中执行 SQL 查询,创…...
docker应用:搭建uptime-kuma监控站点
简介:Uptime Kuma是一个易于使用的自托管监控工具,它的界面干净简洁,部署和使用都非常方便。 历史攻略: docker:可视化工具portainer docker-compose:搭建自动化运维平台Spug 开源地址: ht…...
在illustrator中按大小尺寸选择物体 <脚本 018>
在Illustrator中我们可以依据对象的属性 如:填充颜色、描边颜色或描边宽度来选择相同属性的对象,但是Illustrator中没有根据不同大小尺寸来选择对象的功能,下面介绍的就是根据大小尺寸选择对象的脚本。 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…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...
基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制
目录 节点的功能承载层(GATT/Adv)局限性: 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能,如 Configuration …...
Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
