React16源码: React中的expirationTime过期时间的计算源码实现
expirationTime 的计算方式
- 先看expirationTime相关的源代码,这里是异步的计算方式,它会有一个过期时间
- 异步任务优先级比较低,可以被打断,防止一直被打断导致不能执行,所以React给它设置了 expirationTime 过期时间
- 也就是在这个时间之前,都可以打断,但是如果某个时间点发现任务已经过期了,还没有被执行,则强制执行该任务
- 在
ReactDOM.render当中,它计算 expirationTime 的地方- 在 ReactFiberReconciler.js 中的
updateContainer函数中,通过computeExpirationForFiber方法来计算一个过期时间const current = container.current; // 参数2 const currentTime = requestCurrentTime(); // 参数1 我们可以近似理解为: 当前时间到js加载完成的时间的时间差值即可 const expirationTime = computeExpirationForFiber(currentTime, current); - 而
requestCurrentTime这个函数,来自于 ReactFiberScheduler.js 中function requestCurrentTime() {// 这里,我把官方注释移除// 这里表示 已经进入到 渲染阶段 了,在 ReactDOM.render 中这里不会匹配,会跳过// 在一次render中,如果我有一个新的任务进来了,要计算 expirationTime 发现现在处于渲染阶段,这时直接返回上次 render 开始的时间,再去计算 expirationTime// 好处是 前后两次计算出来的 expirationTime 是一样的,让这个任务提前进行调度if (isRendering) {// We're already rendering. Return the most recently read time.return currentSchedulerTime;}// Check if there's pending work.findHighestPriorityRoot();// 刚初始化的时候,这个条件是成立的if (nextFlushedExpirationTime === NoWork ||nextFlushedExpirationTime === Never) {// If there's no pending work, or if the pending work is offscreen, we can// read the current time without risk of tearing.recomputeCurrentRendererTime();currentSchedulerTime = currentRendererTime; // 两个常量划等号return currentSchedulerTime;}// 这里,我把官方注释移除return currentSchedulerTime; }findHighestPriorityRoot方法涉及到从调度队列中找到权限最高的 Root- 这个源码比较多,不做扩展
recomputeCurrentRendererTime每一次做计算都是从当前到js加载完成后的时间间隔,再经过一些计算得到的值,function recomputeCurrentRendererTime() {const currentTimeMs = now() - originalStartTimeMs; // 当前时间 - react buddle加载完成之后初始的时间,也就是从js加载完成到现在的时间间隔currentRendererTime = msToExpirationTime(currentTimeMs); // 计算出 currentRendererTime }// ReactFiberExpirationTime.js 这个函数得到一个时间戳 export function msToExpirationTime(ms: number): ExpirationTime {// Always add an offset so that we don't clash with the magic number for NoWork.return ((ms / UNIT_SIZE) | 0) + MAGIC_NUMBER_OFFSET; // UNIT_SIZE 是固定的 10, | 0 是取整的意思, MAGIC_NUMBER_OFFSET 是固定的 2 }
- 关于
expirationTime的计算函数computeExpirationForFiber有一个计算公式 - 在这个计算时间中,不需要考虑调度,只考虑计算公式,在 ReactFiberExpirationTime.js 中
function ceiling(num: number, precision: number): number {return (((num / precision) | 0) + 1) * precision; }function computeExpirationBucket(currentTime,expirationInMs,bucketSizeMs, ): ExpirationTime {return (MAGIC_NUMBER_OFFSET +ceiling(currentTime - MAGIC_NUMBER_OFFSET + expirationInMs / UNIT_SIZE,bucketSizeMs / UNIT_SIZE,)); }// 低权限计算 export function computeAsyncExpiration(currentTime: ExpirationTime, ): ExpirationTime {return computeExpirationBucket(currentTime,LOW_PRIORITY_EXPIRATION, // 5000LOW_PRIORITY_BATCH_SIZE, // 250); }// 高权限计算 export function computeInteractiveExpiration(currentTime: ExpirationTime) {return computeExpirationBucket(currentTime,HIGH_PRIORITY_EXPIRATION, // 500/150 前 DEV, 后 PRODHIGH_PRIORITY_BATCH_SIZE, // 100); }- 上面两个 export 方法,都是调用
computeExpirationBucket方法来计算的 - 两个方法的区别在于 后面第2和第3个参数是不一样的
- 最终得到的公式是:
((((currentTime - 2 + 5000 / 10) / 25) | 0 ) + 1) * 25- 其中 25 = 250 / 10,上述公式中的25,也可能是 10 (100 / 10)
- 最终计算出来的
expirationTime是以bucketSize / UNIT_SIZE这个单元向上叠加的 - 两个 不同的
expirationTime的差距是 单元值的 倍数 - 对于
LOW_PRIORITY_BATCH_SIZE是 以 25 为单元向上加的, 若前后差距在25以内,计算出来的差距都是一样的 - 对于
HIGH_PRIORITY_BATCH_SIZE是 以 10 为单元向上加的,同上 - React 这么设定的原因: 在计算
expirationTime时 - 在一个操作内多次调用
setState, 即便前后调用差距很小,但从毫秒级别看,还是有差距的 - 如果没有提供任何一个调整空间,即便上个
setState和 下一个setState之间差距特别小,算出来的expirationTime结果不一样 - 这就意味着,两次的任务优先级不一样, 会导致 React 整体更新执行多次,而导致整个应用的性能下降,这就是 设置 单元值的 用处
- 在一个差距很小的时间间隔内,算出来的
expirationTime结果一样,则它们优先级也是一样的,而不需要进行区分 - 这个非常重要
- 最终计算出来的
| 0表示 去余取整- 其中 (currentTime - 2 + 5000 / 10) 是一个不会变化的值,设为 x
- 后面就是 (((x / 25) | 0) + 1) * 25
- 这个公式的意义在于,新老值之间的差距在25以内,则结果相等
- 其中 25 = 250 / 10,上述公式中的25,也可能是 10 (100 / 10)
- 上面两个 export 方法,都是调用
- 在 ReactFiberReconciler.js 中的
- 至于
expirationTime的作用还要结合后期更新的流程来看 expirationTime是一个和业务无关的比较纯粹的计算过程问题,没有任何副作用
相关文章:
React16源码: React中的expirationTime过期时间的计算源码实现
expirationTime 的计算方式 先看expirationTime相关的源代码,这里是异步的计算方式,它会有一个过期时间异步任务优先级比较低,可以被打断,防止一直被打断导致不能执行,所以React给它设置了 expirationTime 过期时间也…...
程序设计语言的分类
编译与解释 编译型 将源代码转换成目标代码,通常源代码是高级语言代码,目标代码是机器语言代码,执行编译的计算机程序称为编译器。 eg:java 好处:对于相同的源代码编译产生的目标代码执行速度更快,目标代码不需要编译…...
Python轻松实现炫酷的手势检测
大家好,今天分享一个非常有意思且十分简单的python库——mediapipe库。该库集成了大量的深度学习模型,短短几行代码,就可以快速实现一个炫酷的实例,本文就以手势检测为例,展示一下这个强大的开源库。 mediapipe由Goog…...
什么是信噪比
大家好,今天给大家介绍什么是信噪比,文章末尾附有分享大家一个资料包,差不多150多G。里面学习内容、面经、项目都比较新也比较全!可进群免费领取。 “信噪比”是电子技术中经常用到的一个词组,知道它的确切含义有一定意…...
学习redis有效期和数据类型
1、安装redis和连接redis 参考:ubuntu安装单个redis服务_ubuntu redis单机版安装-CSDN博客 连接redis:redis-cli.exe -h localhost -p 6379 -a 123456 2、Redis数据类型 以下操作我们在图形化界面演示。 2.1、五种常用数据类型介绍 Redis存储的是key…...
【linux】进程管理
前言 linux也有类似于windows的任务管理器的功能,我们也可以通过这个功能查看当前的进程情况。 语法 ps [-e] [-f] -e显示所有进程 -f显示完整的信息 我们可以直接用-ef来简化指令。 案例演示 信息过滤 但是如果我们直接这么输入的话,可以看到他回复…...
k8s operator从0到1实践
文章目录 环境准备一个k8s集群开发工具包mac安装 实践初始化operator项目核心逻辑编写测试验证验证 部署 参考 环境准备 一个k8s集群 推荐使用docker-desktop,本地单机集群 开发工具包 这里推荐使用脚手架工具kubebuilder 使用脚手架工具,能生成项目…...
【动态规划】dp多状态问题
欢迎来到Cefler的博客😁 🕌博客主页:那个传说中的man的主页 🏠个人专栏:题目解析 🌎推荐文章:【LeetCode】winter vacation training 目录 👉🏻按摩师👉&…...
docker安裝gocd-server,并配置gitlab授权登录
gocd的地址:Installing GoCD server on Windows | GoCD User Documentation gocd文档:GitHub - gocd/docker-gocd-server: Docker server image for GoCD 一、docker拉取gocd镜像 #拉取server镜像 docker pull gocd/gocd-server:v21.1.0docker pull g…...
使用pygame实现简单的烟花效果
import pygame import sys import random import math# 初始化 Pygame pygame.init()# 设置窗口大小 width, height 800, 600 screen pygame.display.set_mode((width, height)) pygame.display.set_caption("Fireworks Explosion")# 定义颜色 black (0, 0, 0) wh…...
ubantu系统运维命令,端口相关操作
1、使用sudo ufw status命令查看所有开放的端口,如下图: 2、使用命令sudo ufw allow 8443,打开端口8443.如下图: 3、使用 sudo ufw reload刷新端口配置,如下图:...
Java中的Stream API进阶使用
Java的Stream API是Java 8引入的一个强大的功能,它允许以声明性方式处理数据集合,例如过滤、映射、排序等。下面是一些Stream API的进阶使用: 自定义中间操作:你可以定义自己的中间操作,然后在Stream上使用它。例如&am…...
R语言【paleobioDB】——pbdb_collection():从PBDB获取单个采集号的基本信息
Package paleobioDB version 0.7.0 paleobioDB 包在2020年已经停止更新,该包依赖PBDB v1 API。 可以选择在Index of /src/contrib/Archive/paleobioDB (r-project.org)下载安装包后,执行本地安装。 Usage pbdb_collection (id, ...) Arguments 参数【…...
阿里云服务器的tcp端口无法访问(云服务厂家问题?)
问题->无法访问 阿里云服务器的tcp端口 最近一台阿里云服务器的一个端口61616无法访问,在服务器内用外网地ip发现无法访问,用内网ip访问是正常的,通过技术排查: 解决->无法访问 阿里云服务器的tcp端口 1 配置官网的安全组…...
BikeDNA(九) 特征匹配
BikeDNA(九) 特征匹配 特征匹配采用参考数据并尝试识别 OSM 数据集中的相应特征。 特征匹配是比较单个特征而不是研究区域网格单元水平上的特征特征的必要前提。 方法 将两个道路数据集中的特征与其数字化特征的方式以及边缘之间潜在的一对多关系进行…...
vuex是什么?怎么使用?哪种功能场景使用它?
Vuex是Vue.js官方推荐的状态管理库,用于在Vue应用程序中管理和共享状态。它基于Flux架构和单向数据流的概念,将应用程序的状态集中管理,使得状态的变化更可追踪、更易于管理。Vuex提供了一个全局的状态树,以及一些用于修改状态的方…...
求斐波那契数列矩阵乘法的方法
斐波那契数列 先来简单介绍一下斐波那契数列: 斐波那契数列是指这样一个数列:1,1,2,3,5,8,13,21,34,55,89……这个数列从第3项开始 &…...
【IPC通信--消息队列】
消息队列(也叫做报文队列)是一个消息的链表。可以把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读走消息…...
读写分离的手段——主从复制,解决读流量大大高于写流量的问题
应用场景 假设说有这么一种业务场景,读流量显著高于写流量,你要怎么优化呢。因为写是要加锁的,可能就会阻塞你读请求。而且其实读多写少的场景还很多见,比如电商平台,用户浏览n多个商品才会买一个。 大部分人的思路可…...
Day02
今日任务: 977 有序数组的平方209 长度最小的子数组59 螺旋矩阵Ⅱ 977 有序数组的平方 题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/ 双指针问题,以及数组本身时有序的; 思路: 左、右两个…...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
