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以内,则结果相等
  • 至于 expirationTime 的作用还要结合后期更新的流程来看
  • expirationTime 是一个和业务无关的比较纯粹的计算过程问题,没有任何副作用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/609832.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于java的冒泡排序

关于java的冒泡排序 我们前面的文章中了解到了数组的方法类Arrays,我们本篇文章来了解一下最出名的排序算法之一,冒泡排序!😀 冒泡排序的代码还是非常简单的,两层循环,外层冒泡轮数,里层依次比…

PCL 点云八叉树包围盒搜索

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 这个操作第一个感觉就是非常适合一些点云裁切操作,有时候我们希望获取一个包围盒范围内所包含的点云,这个操作可以帮我们实现这一点,不过八叉树的包围盒默认是AABB包围盒,想要适用更普遍的情况,还需在此基础上…

TSP(Python):Qlearning求解旅行商问题TSP(提供Python代码)

一、Qlearning简介 Q-learning是一种强化学习算法,用于解决基于奖励的决策问题。它是一种无模型的学习方法,通过与环境的交互来学习最优策略。Q-learning的核心思想是通过学习一个Q值函数来指导决策,该函数表示在给定状态下采取某个动作所获…

【操作系统】复习汇总(各章节知识图谱)

第1章: 第2章: 第3章: 第4章: 第5章: 第6章: 第7章: 第8章: 第9章:

系统性介绍MoE模型架构,以及在如今大模型方向的发展现状

知乎:Verlocksss编辑:马景锐链接:https://zhuanlan.zhihu.com/p/675216281 1 学习动机 第一次了解到MoE(Mixture of experts),是在GPT-4模型架构泄漏事件,听说GPT-4的架构是8个GPT-3级别大小的模…

2707. 字符串中的额外字符

牛客网:https://leetcode.cn/problems/extra-characters-in-a-string/description/?envTypedaily-question&envId2024-01-09 官方解题思路为动态规划或字典数优化; 这里引入Up主的解题思路(递归) 哔哩哔哩:https…

【计算机网络】TCP原理 | 可靠性机制分析(二)

个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【网络编程】【Java系列】 本专栏旨在分享学习网络编程、计算机网络的一点学习心得,欢迎大家在评论区交流讨论💌 T…

Python异步编程|PySimpleGUI界面读取PDF转换Excel

目录 实例要求 原始pdf文件格式 输出xls文件格式 运行界面 完整代码 代码分析 遍历表格 布局界面 控件简介 写入表格 表格排序 事件循环 异步编程 实例要求 使用PySimpleGUI做一个把单位考勤系统导出的pdf文件合并输出Excel的应用,故事出自&#xff1…

UGUI Button 退出应用或退出编辑器当前运行状态

代码退出当前编辑器运行状态测试正常。 Unity3d引擎版本:Uinty3d 20233.2.3f1 脚本代码: using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; public class btnCloseScript : MonoBeh…

CDN的介绍以及加速内容传输原理

目前在公司的开发过程中,发现很多存储在oss的静态资源(图片,安装包)的链接中域名都使用了cdn域名,后面了解到这个cdn域名的主要作用是加速资源的访问,于是抽空了解了一下CDN加速原理。 目前使用得比较多的是…

Python多线程同步

同步条件(Event) 在Python中,多线程同步可以通过threading模块中的Event对象来实现。Event对象允许一个或多个线程等待某个事件的发生,当事件发生时,等待的线程将被唤醒。 event.isSet():返回event的状态值 event.wait()&#x…

PyQt5-小总结

之前学习PyQt5,然后那段时间想做一个桌面小程序,后来由于学习内容较多就做了一小部分,但是可以进行页面跳转。大家如果是初学者对Python感兴趣而且刚学数据库时可以看看代码,可能会有点启发。 效果: 登录进来是这&…

FreeRTOS学习——任务通知

一、什么是任务通知 FreeRTOS 从版本 V8.2.0 开始提供任务通知这个功能,每个任务都有一个 32 位的通知值。按照 FreeRTOS 官方的说法,使用消息通知比通过二进制信号量方式解除阻塞任务快 45%, 并且更加省内存(无需创建队 列&#…

解析游戏开发中的ECS设计模式:实体、组件、系统的完美协同

ECS(Entity-Component-System)是一种设计模式,通常用于构建和管理具有大量实体和复杂交互的系统,尤其在游戏开发中得到广泛应用。这个模式的核心思想是将系统中的组件、实体和系统进行分离,以提高代码的可维护性、可扩…

vue element plus 快速开始

本节将介绍如何在项目中使用 Element Plus。 用法# 完整引入# 如果你对打包后的文件大小不是很在乎,那么使用完整导入会更方便。 // main.ts import { createApp } from vue import ElementPlus from element-plus import element-plus/dist/index.css import A…

Java线程池七个参数详解

前言 直接点题 核心线程数 - corePoolSize 最大线程数 - maximumPoolSize 空闲线程存活时间 - keepAliveTime 存活时间单位 - unit 任务队列 - workQueue 线程工厂 - threadFactory 拒绝策略- handler 概念 什么是池? 池(Pool)&…

haiku实现门控多头注意力模块

在多头注意力机制中,通常输入的数据包括查询(Q)、键(K)和值(V)。这些数据的维度以及权重矩阵的维度在多头注意力机制中扮演关键角色。下面对数据及权重的维度进行解释: 输入数据&…

鸿蒙原生应用/元服务开发-长时任务

概述 功能介绍 应用退至后台后,对于在后台需要长时间运行用户可感知的任务,例如播放音乐、导航等。为防止应用进程被挂起,导致对应功能异常,可以申请长时任务,使应用在后台长时间运行。申请长时任务后,系统…

Linux调试------gdb的使用

目录 前言 一、gdb打开可执行程序 二、查看代码与操作断点 1.l 查看代码 2.b 打断点 3.info b 查看断点信息 4.d 删除断点 5.disable 和 enable 断点的禁用与启用 三、调试 1.r 启动调试 2. n 逐过程 3. s 逐语句 4.display显示变量 5.undisplay 取消显…

e2studio开发磁力计LIS2MDL(1)----轮询获取磁力计数据

e2studio开发磁力计LIS2MDL.1--轮询获取磁力计数据 概述视频教学样品申请源码下载速率新建工程工程模板保存工程路径芯片配置工程模板选择时钟设置UART配置UART属性配置设置e2studio堆栈e2studio的重定向printf设置R_SCI_UART_Open()函数原型回调函数user_uart_callback ()prin…