React16源码: React中requestCurrentTime和expirationTime的源码实现补充
requestCurrentTime
1 )概述
- 关于 currentTime,在计算 expirationTime 和其他的一些地方都会用到
- 从它的名义上来讲,应等于performance.now() 或者 Date.now() 就是指定的当前时间
- 在react整体设计当中,它是有一些特定的用处和一些特殊的设定的
- 比如说在一次渲染中产生的更新,需要使用相同的时间
- 在一次批处理的更新中,应该得到相同的时间
- 还有就是挂起的任务用于记录的时候,应该也是相同的
2 )源码
function requestCurrentTime() {// requestCurrentTime is called by the scheduler to compute an expiration// time.//// Expiration times are computed by adding to the current time (the start// time). However, if two updates are scheduled within the same event, we// should treat their start times as simultaneous, even if the actual clock// time has advanced between the first and second call.// In other words, because expiration times determine how updates are batched,// we want all updates of like priority that occur within the same event to// receive the same expiration time. Otherwise we get tearing.//// We keep track of two separate times: the current "renderer" time and the// current "scheduler" time. The renderer time can be updated whenever; it// only exists to minimize the calls performance.now.//// But the scheduler time can only be updated if there's no pending work, or// if we know for certain that we're not in the middle of an event.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;}// There's already pending work. We might be in the middle of a browser// event. If we were to read the current time, it could cause multiple updates// within the same event to receive different expiration times, leading to// tearing. Return the last read time. During the next idle callback, the// time will be updated.return currentSchedulerTime;
}
- 第一种情况,在
isRendering的时候,会直接返回currentSchedulerTime, 这个 schedulerTime- 而
isRendering只有在performWorkOnRoot的时候才被设置为 true - 而 performWorkOnRoot 是在 performWork 中被循环调用的
- performWorkOnRoot 的前后,都会重设
currentSchedulerTime - 这样,在 performWorkOnRoot 的时候, isRendering 被设定为 true,并且是一个同步的方法
- 使用 performWorkOnRoot 的时候, 后期会调用 render 和 commit 两个阶段
- 在上述两个阶段里,都有可能调用组件的生命周期方法,在这里有可能产生更新
- react的设定是,在当前渲染流程中,如果在生命周期方法里触发了新的更新
- 那么它计算 expirationTime 的时间,需要一个固定的时间,所以统一返回
currentSchedulerTime - 这个
currentSchedulerTime就是在调用 performWorkOnRoot 之前算出来的时间 - requestCurrentTime 的
if (isRendering) return currentScheudlerTime的设定
- 而
- 第二种情况
- 调用
findHighestPriorityRoot找到调度队列中,优先级最高的任务 - 如果符合
if (nextFlushedExpirationTime === NoWork || nextFlushedExpirationTime === Never)- 目前没有任务进行或正在更新的组件是从未展现的组件
- 这时候,重新计算 renderTime
recomputeCurrentRendererTime(); - 并且赋值
currentSchedulerTime = currentRendererTime; - 最终 return currentSchedulerTime
- 这里和
batchedUpdates里面类似- 创建了 事件的回调,多次调用 setState 会创建多个更新
- 计算多次 expirationTime
- 如果没有做这类处理
requestCurrentTime都去计算一个时间 - 就会导致返回的时间不一致,因为时间不一致,导致计算出来的 expirationTime不一致
- 那么就导致任务优先级不一致,它们会分批次的进行更新,就会导致问题
- 在异步的模式下,即便只有在最后一次,回调调用完之后才会去调用 performWork
- 但是因为任务优先级不同,会导致分多次进行调用
- 所以,通过上述判断来规避此类问题
- 第一次调用 setState 之后,就在一个root上创建一个更新
- 从 firstScheduledRoot 到 lastScheduledRoot 里面至少会有一个
- 即将要执行的更新,在有一个的情况下,上述 if 就不满足了,就不会直接计算时间
- 直接返回 currentSchedulerTime 这个已保存的时间
- 调用
expirationTime
1 ) 概述
- 在计算 expirationTime 之前,我们计算的时间是预先处理过的
- 在 requestCurrentTime 函数中有一个
recomputeCurrentRendererTime
2 )源码
// /packages/react-reconciler/src/ReactFiberScheduler.js
function recomputeCurrentRendererTime() {const currentTimeMs = now() - originalStartTimeMs;currentRendererTime = msToExpirationTime(currentTimeMs);
}// packages/react-reconciler/src/ReactFiberExpirationTime.js
// 1 unit of expiration time represents 10ms.
export function msToExpirationTime(ms: number): ExpirationTime {// Always add an offset so that we don't clash with the magic number for NoWork.// ms / UNIT_SIZE 为了防止 10ms 之内的误差,两个时间差距在10ms以内,两个时间看做一致,最终计算出来的优先级也是一致return ((ms / UNIT_SIZE) | 0) + MAGIC_NUMBER_OFFSET; // UNIT_SIZE 是 10, const MAGIC_NUMBER_OFFSET 是 2
}
function computeExpirationBucket(currentTime,expirationInMs,bucketSizeMs,
): ExpirationTime {return (MAGIC_NUMBER_OFFSET +ceiling(currentTime - MAGIC_NUMBER_OFFSET + expirationInMs / UNIT_SIZE,bucketSizeMs / UNIT_SIZE,));
}
export function expirationTimeToMs(expirationTime: ExpirationTime): number {return (expirationTime - MAGIC_NUMBER_OFFSET) * UNIT_SIZE;
}
- 在后续 computeExpirationBucket 中
currentTime - MAGIC_NUMBER_OFFSET - 所以 MAGIC_NUMBER_OFFSET 没有影响到 真正时间的计算
- 误差在10ms以内的,前后两个用于计算 expirationTime 的 currentTime
- 它们的误差会被抹平,就是 msToExpirationTime 这个方法被设计的意义
- 最终使用具体的时间设置timeout, 判断是否过期的时候,会通过
expirationTimeToMs把这个时间转回来
相关文章:
React16源码: React中requestCurrentTime和expirationTime的源码实现补充
requestCurrentTime 1 )概述 关于 currentTime,在计算 expirationTime 和其他的一些地方都会用到 从它的名义上来讲,应等于performance.now() 或者 Date.now() 就是指定的当前时间在react整体设计当中,它是有一些特定的用处和一些…...
【论文阅读】Deep Graph Contrastive Representation Learning
目录 0、基本信息1、研究动机2、创新点3、方法论3.1、整体框架及算法流程3.2、Corruption函数的具体实现3.2.1、删除边(RE)3.2.2、特征掩盖(MF) 3.3、[编码器](https://blog.csdn.net/qq_44426403/article/details/135443921)的设…...
设计模式-简单工厂
设计模式-简单工厂 简单工厂模式是一个集中管理对象创建,并根据条件生成所需类型对象的设计模式,有助于提高代码的复用性和维护性,但可能会导致工厂类过于复杂且违反开闭原则。 抽象提取理论: 封装对象创建过程解耦客户端与产品…...
Django ORM 中的单表查询 API(1)
在 Django 中,对象关系映射(ORM)提供了一种功能强大、表现力丰富的数据库交互方式。ORM 允许开发人员使用高级 Python 代码执行数据库查询,从而更轻松地处理数据库实体。 下面,我们将探讨 Django ORM 中单表查询 API …...
电子雨html代码
废话不多说下面是代码: <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><title>Code</title><style>body{margin: 0;overflow: hidden;}</style></head><body><c…...
xadmin基于Django的后台管理系统安装与使用
xadmin是基于Django的后台管理系统 官网:http://sshwsfc.github.io/xadmin/ github地址:https://github.com/sshwsfc/xadmin 安装方式 pip安装 pip install xadmin在setting配置中添加: INSTALLED_APPS [xadmin,crispy_forms, ]在urls.py…...
[go语言]输入输出
目录 知识结构 输入 1.Scan 编辑 2.Scanf 3.Scanln 4.os.Stdin --标准输入,从键盘输入 输出 1.Print 2.Printf 3.Println 知识结构 输入 为了展示集中输入的区别,将直接进行代码演示。 三者区别的结论:Scanf格式化输入&#x…...
【SpringBoot系列】AOP详解
🤵♂️ 个人主页:@香菜的个人主页,加 ischongxin ,备注csdn ✍🏻作者简介:csdn 认证博客专家,游戏开发领域优质创作者,华为云享专家,2021年度华为云年度十佳博主 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞👍🏻 收…...
openssl3.2 - 官方demo学习 - signature - rsa_pss_hash.c
文章目录 openssl3.2 - 官方demo学习 - signature - rsa_pss_hash.c概述笔记END openssl3.2 - 官方demo学习 - signature - rsa_pss_hash.c 概述 对私钥对明文做签名(摘要算法为SHA256) 用公钥对密文做验签(摘要算法为SHA256) 笔记 /*! \file rsa_pss_hash.c \note openss…...
Redis相关知识点
1.什么是Redis Redis (REmote DIctionary Server) 是用 C 语言开发的一个开源的高性能键值对(key-value)数据库,它支持网络,可基于内存亦可持久化,并提供多种语言的API。Redis具有高效性、原子性、支持多种数据结构、…...
嵌入式开发--STM32G4系列片上FLASH的读写
这个玩意吧,说起来很简单,就是几行代码的事,但楞是折腾了我大半天时间才搞定。原因后面说,先看代码吧: 读操作 读操作很简单,以32位方式读取的时候是这样的: data *(__IO uint32_t *)(0x080…...
嵌入式-Stm32-江科大基于标准库的GPIO的八种模式
文章目录 一:GPIO输入输出原理二:GPIO基本结构三:GPIO位结构四:GPIO的八种模式道友:相信别人,更要一百倍地相信自己。 (推荐先看文章:《 嵌入式-32单片机-GPIO推挽输出和开漏输出》…...
2024年1月17日Arxiv热门NLP大模型论文:THE FAISS LIBRARY
Meta革新搜索技术!提出Faiss库引领向量数据库性能飞跃 引言:向量数据库的兴起与发展 随着人工智能应用的迅速增长,需要存储和索引的嵌入向量(embeddings)数量也在急剧增加。嵌入向量是由神经网络生成的向量表示&…...
深度解析JVM类加载器与双亲委派模型
概述 Java虚拟机(JVM)是Java程序运行的核心,其中类加载器和双亲委派模型是JVM的重要组成部分。本文将深入讨论这两个概念,并解释它们在实际开发中的应用。 1. 什么是类加载器? 类加载器是JVM的一部分,负…...
前端下载文件流,设置返回值类型responseType:‘blob‘无效的问题
前言: 本是一个非常简单的请求,即是下载文件。通常的做法如下: 1.前端通过Vue Axios向后端请求,同时在请求中设置响应体为Blob格式。 2.后端相应前端的请求,同时返回Blob格式的文件给到前端(如果没有步骤…...
C++核心编程——类和对象(一)
本专栏记录C学习过程包括C基础以及数据结构和算法,其中第一部分计划时间一个月,主要跟着黑马视频教程,学习路线如下,不定时更新,欢迎关注。 当前章节处于: ---------第1阶段-C基础入门 ---------第2阶段实战…...
脱模斜度是什么意思,为什么要有脱模斜度,没有斜度不行吗?
问题描述:脱模斜度是什么意思,为什么要有脱模斜度,没有斜度不行吗? 问题解答: 脱模斜度是指在模具中的零件在脱模(从模具中取出)过程中相对于模具开合方向的倾斜程度。在模具设计和制造中&…...
【现代密码学】笔记9-10.3-- 公钥(非对称加密)、混合加密理论《introduction to modern cryphtography》
【现代密码学】笔记9-10.3-- 公钥(非对称加密)、混合加密理论《introduction to modern cryphtography》 写在最前面8.1 公钥加密理论随机预言机模型(Random Oracle Model,ROM) 写在最前面 主要在 哈工大密码学课程 张…...
牛客-寻找第K大、LeetCode215. 数组中的第K个最大元素【中等】
文章目录 前言牛客-寻找第K大、LeetCode215. 数组中的第K个最大元素【中等】题目及类型思路思路1:大顶堆思路2:快排二分随机基准点 前言 博主所有博客文件目录索引:博客目录索引(持续更新) 牛客-寻找第K大、LeetCode215. 数组中的第K个最大元…...
MySQL的各种日志
目录 一、错误日志 二、二进制日志 1、介绍 2、作用 3、相关信息 4、日志格式 5、查看二进制文件 6、二进制日志文件删除 三、查询日志 四、慢日志 一、错误日志 记录MySQL在启动和停止时,以及服务器运行过程中发生的严重错误的相关信息,当数据库…...
影刀RPA 从0到1:自动化系统架构收敛与工程化演进总结
影刀RPA 从0到1:自动化系统架构收敛与工程化演进总结 作者:林焱 写到这里。 这个系列其实已经慢慢进入后半段了。 前面聊了很多内容。 包括: 浏览器池 节点集群 Redis 队列 调度系统 容灾恢复 日志监控 性能治理 很多人刚开始接…...
HTTPS一文通
https 的出现,为解决网络加密通信提供了完美的解决方案。现在得到了非常普遍的运用。但 https 的原理和部署方式还存在一些较迷惑的点。 一、基础数学知识 在普通的http通讯过程中,前端浏览器和服务器之间传递的都是明文,这样敏感信息就容易被…...
保姆级教程:在RK3588开发板上用Python部署NanoTrack,实测120FPS真香
保姆级教程:在RK3588开发板上用Python部署NanoTrack,实测120FPS真香 RK3588作为当前嵌入式AI领域的旗舰级芯片,其强大的NPU算力让边缘设备也能流畅运行复杂的视觉算法。本文将手把手带你完成NanoTrack模型从转换到部署的全流程,实…...
C++位运算技巧应用
C位运算技巧应用位运算是直接操作二进制位的运算,具有极高的执行效率。掌握位运算技巧可以优化算法性能并实现紧凑的数据表示。基本位运算包括与、或、异或、取反和移位操作。#include #includevoid basic_bitwise_operations() { unsigned int a 0b1010; unsigned…...
别再只算差异了!用Cytoscape给Hub Gene分析加个‘可视化Buff’(附脑网络实战图)
别再只算差异了!用Cytoscape给Hub Gene分析加个‘可视化Buff’(附脑网络实战图) 在生物信息学分析中,差异基因筛选往往是研究的第一步,但如何从海量差异基因中找出真正具有生物学意义的"关键调控者"…...
用VMware虚拟机也能玩转PX4无人机仿真?保姆级配置流程与性能优化心得
在VMware虚拟机中高效运行PX4无人机仿真的完整指南 对于许多无人机开发者和爱好者来说,搭建PX4仿真环境是入门的第一步。然而,并非所有人都有条件使用专用硬件或安装双系统。本文将详细介绍如何在VMware虚拟机上配置Ubuntu 18.04系统,并优化P…...
vue3+python基于Django框架的铁路博物馆展览系统的设计与实现67350649
目录同行可拿货,招校园代理 ,本人源头供货商项目背景技术栈核心功能模块关键技术实现部署方案项目亮点项目技术支持源码获取详细视频演示 :同行可合作点击我获取源码->->进我个人主页-->获取博主联系方式同行可拿货,招校园代理 ,本人源头供货商 项目背景 …...
机器学习论文阅读的解码协议:从扫读到复现的四步实战法
1. 为什么读论文这件事,比写代码还容易让人焦虑“How to Read Machine Learning Papers Effectively”——这个标题乍看像是一篇方法论指南,但在我带过三十多个算法实习生、审过两百多份顶会投稿、自己连续七年保持每周精读2–3篇NeurIPS/ICML/ACL论文的…...
2021年5月AI工程落地三大技术水位观测
1. 项目概述:这不是一份榜单,而是一份2021年5月AI技术落地的“现场目击报告”“The AI Monthly Top 3 — May 2021”这个标题乍看像一份轻量级行业简报,但如果你在2021年真正泡在AI工程一线,就会明白它背后沉甸甸的分量。那会儿&a…...
TVA:打通数字AI到物理AI的关键桥梁(系列)
重磅预告:本专栏将独家连载系列丛书《智能体视觉技术与应用》部分精华内容,该书是世界首套系统阐述“因式智能体”视觉理论与实践的专著,特邀美国 TypeOne 公司首席科学家、斯坦福大学博士 Bohan 担任技术顾问。Bohan先生师从美国三院院士、“…...
