React18源码: schedule任务调度messageChannel
React调度原理(scheduler)
- 在React运行时中,调度中心(位于scheduler包)
- 是整个React运行时的中枢(其实是心脏),所以理解了scheduler调度,就基本掌握了React的核心
- React两大循环:从宏观的角度介绍 React 体系中两个重要的循环,其中任务调度循环就是本文的主角
- Reconciler 运行流程从宏观的角度描述了 react-reconciler 包的核心作用
- 并把 reconciler 分为了4个阶段
- 其中第 2 个阶段注册调度任务串联了 scheduler 包和 react-reconciler 包
- 其实就是任务调度循环中的一个任务(task)
- 优先级管理
- React体系中的3中优先级的管理
- 着重源码中react-reconciler与scheduler包中关于优先级的转换思路
- 其中 SchedulerPriority 控制任务调度循环中循环的顺序
调度实现
调度中心最核心的代码,在 SchedulerHostConfig.default.js 中
内核
- 该js文件一共导出了8个函数,最核心的逻辑,就集中在了这8个函数中
export let requestHostCallback; // 请求及时回调: port.postMessage export let cancelHostCallback; // 取消及时回调: scheduledHostCallback = null export let requestHostTimeout; // 请求延时回调: setTimeout export let cancelHostTimeout; // 取消延时回调: cancelTimeout export let shouldYieldToHost; // 是否让出主线程 (currentTime >- deadline && needsPaint): export let requestPaint; // 请求绘:设置 needsPaint = true export let getCurrentTime; // 获取当前间 export let forceFrameRate; // 强制设置 yieldIntervol (让出主线程的周期) - react可以在nodejs环境中使用,所以在不同的js执行环境中,这些函数的实现会有区别
- 下面基于普通浏览器环境,对这8个函数逐一分析
1 )调度相关:请求或取消调度
-
requestHostCallback -
cancelHostCallback -
requestHostTimeout -
cancelHostTimeout -
这4个函数源码很简洁,非常好理解,它们的目的就是请求执行(或取消)回调函数
-
现在重点介绍其中的及时回调 (延时回调的2个函数暂时属于保留api,17.0.2版本其实没有用上)
// MessageChannel const performWorkUntilDeadline=() => {//...省略无关代码if (scheduledHostCallback !== null) {const currentTime = getCurrentTime();// 更新 deadlinedeadline = currentTime + yieldInterval;// 执行 callbackscheduledHostCallback(hasTimeRemaining, currentTime);} else {isMessageLoopRunning = false;}; };const channel = new MessageChannel(); const port = channel.port2; channel.port1.onmessage = performWorkUntilDeadline;// 请求回调 requestHostCallback = function(callback) {// 1.保存callbackscheduledHostCallback = callback;if(!isMessageLoopRunning) {isMessageLoopRunning= true;// 2.通过 MessageChannel消息port.postMessage(null);} };// 取消回调 cancelHostCallback = function() {scheduledHostCallback = null; } -
很明显,请求回调之后 scheduledHostCallback = callback
-
然后通过MessageChannel发消息的方式触发performWorkUntilDeadline函数
-
最后执行回调 scheduledHostCallback
-
此处需要注意
- MessageChannel在浏览器事件循环中属于宏任务
- 所以调度中心永远是异步执行回调函数
2 )时间切片(timeslicing)相关:
-
执行时间分割,让出主线程
-
把控制权归还浏览器,浏览器可以处理用户输入,UI绘制等紧急任务
-
getCurrentTime: 获取当前时间 -
shouldYieldToHost: 是否让出主线程 -
requestPaint: 请求绘制 -
forceFrameRate: 强制设置yieldInterval(从源码中的引用来看,算一个保留函数,其他地方没有用到)const localPerformance = performance; // 获取当前时间 getCurrentTime = () => localPerformance.now();// 时间切片周期,默认是5ms(如果一个task运行超过该周期,下一个task执行之前,会把控制权归还浏览器) let yieldInterval = 5; let deadline = 0; const maxYieldInterval = 300; let needsPaint = false; const scheduling = navigator.scheduling; // 是否让出主线程 shouldYieldToHost = function() {const currentTime = getCurrentTime();if (currentTime >= deadline) {if (needsPaint || scheduling.isInputPending()) {// There is either a pending paint or a pending input.return true;}// There's no pending input. Only yield if we've reached the max// yield interval.return currentTime >= maxYieldInterval; // 在持续运行的react应用中, currentTime肯定大于300ms} else {// There's still time left in the frame.return false;} };// 请求绘制 requestPaint = function() {needsPaint = true; };// 设置时间切片的周期 forceFrameRate = function(fps) {if (fps < 0 || fps > 125) {// Using console['error'] to evade Babel and ESLintconsole['error']('forceFrameRate takes a positive int between 0 and 125, ' +'forcing frame rates higher than 125 fps is not supported',);return;}if (fps > 0) {yieldInterval = Math.floor(1000 / fps);} else {// reset the framerateyieldInterval = 5;}; } -
这4个函数代码都很简洁,其功能在注释中都有解释.
-
注意 shouldYieldToHost 的判定条件:
- currentTime >= deadline: 只有时间超过 deadline 之后才会让出主线程
- 其中 deadline = currentTime + yieldInterval
- yieldInterval 默认是5ms, 只能通过 forceFrameRate 函数来修改
- 如果一个task运行时间超过5ms,下一个task执行之前,会把控制权归还浏览器
-
navigator.scheduling.isInputPending():
- 这facebook官方贡献给 Chromium 的api,现在已经列入W3C标准
- 用于判断是否有输入事件(包括:input框输入事件,点击事件等).
-
看完这8个内部函数,最后浏览一下完整的 performWorkUntilDeadline 回调的实现
const performWorkUntilDeadline = () => {if(scheduledHostCallback !== null) {const currentTime = getCurrentTime(); //1.获取当前时间deadline = currentTime + yieldInterval; //2. 置deadline 当前时间 + 5ms, 也就是5ms超时const hasTimeRemaining = true;try {// 3.执行回调,返回是否有还有剩余任务const hasMoreWork = scheduledHostCallback(hasTimeRemaining, currentTime);if (!hasMoreWork) {// 没有剩余任务,退出isMessageLoopRunning = false;scheduledHostCallback = null;} else {port.postMessage(null); // 有剩余任务,发起新的调度}} catch (error) {port.postMessage(null); // 如有异常,重新发起调度throw error;}} else {isMessageLoopRunning = false;}needsPaint = false; // 重置开关 } -
核心总结,如下图
- MessageChanel 里面是宏任务异步执行
- 在执行的过程中,基于 performWorkUnitlDeadline
- 这个方法在执行任务过程中,有一个变量 hasMoreWork
- 基于这个变量判断是否还有任务,如果还有,则继续往里面注册回调,没有则退出
相关文章:
React18源码: schedule任务调度messageChannel
React调度原理(scheduler) 在React运行时中,调度中心(位于scheduler包)是整个React运行时的中枢(其实是心脏),所以理解了scheduler调度,就基本掌握了React的核心React两大循环:从宏…...
Jmeter 学习目录
Jmeter 所有内容均以学习为主输出内容,按照最小单位和基础进行输出。 如果有看不懂,或者有不明确的内容,欢迎大家留言说明。 Jmeter系列(1)Mac Jmeter下载安装启动 Jmeter系列(2)Jmeter 目录介…...
计算机网络 数据链路层课后题
1.以太网帧有哪些不同的封装格式?他们有何区别和应用场景? 以太网II封装(Ethernet II):以太网II封装是最常用的以太网封装格式,也被称为DIX封装。它在数据链路层首部使用6个字节的目的MAC地址和6个字节的源…...
实现验证码功能
Kaptcha 文章目录 Kaptcha介绍插件使用介绍原理引入依赖生成验证码 验证码小项目初始化前端代码约定前后端交互接口接口定义 介绍 Kaptcha 是Google的⼀个⾼度可配置的实⽤验证码⽣成⼯具 https://code.google.com/archive/p/kaptcha ⽹上有很多⼈甚⾄公司基于Google的kaptc…...
PyQt6的开发流程(密码生成小程序为例)
PyQt6的开发流程(密码生成小程序为例) 文章目录 PyQt6的开发流程(密码生成小程序为例)一、流程介绍与概览1. 界面与逻辑分离的开发流程2. PyQt6的开发流程 二、打开 designer.exe 创建文件三、用QT设计师绘制界面保存成ui1. QT常用…...
思腾云计算中心 | 5千平米超大空间,基础设施完善,提供裸金属GPU算力租赁业务
2021年,思腾合力全资收购包头市易慧信息科技有限公司,正式开启云计算业务。思腾云计算中心占地2400平米,位于包头市稀土高新区,毗邻多家知名企业,地理位置优越,交通便利,是区内重要的信息化产业…...
【Leetcode每日一题】二分查找 - 在排序数组中查找元素的第一个和最后一个位置(难度⭐⭐)(18)
1. 题目解析 Leetcode链接:34. 在排序数组中查找元素的第一个和最后一个位置 这个问题的理解其实相当简单,只需看一下示例,基本就能明白其含义了。 核心在于找到给定目标值所在的数组下标区间,设计一个O(logn)的算法。 2. 算法原…...
远程连接 vscode 出错 “远程主机可能不符合 glibc 和 libstdc++ VS Code 服务器的先决条件”
原因: vscode 版本是 1.86,服务器上的 glibc 和 libstdc 版本不满足 要求(2.28 和 3.4.25)。 解决: 1、下载 1.85.2,解压直接运行 Code.exe。 2、回退 Remote-ssh 到 0.107.1。 参考: vscode 1.86版本远程ssh不兼容旧…...
Maven入门:Java项目构建和管理的利器
Maven入门:Java项目构建和管理的利器 Maven 是一个项目管理和综合工具,它基于项目对象模型(POM)概念。Maven 可以管理项目的构建、报告和文档。以下是一篇介绍 Maven 配置和应用的教程文章。 Maven简介 Maven 使用其核心概念 POM…...
《游戏引擎架构》 -- 学习4
资源及文件系统 文件系统 游戏引擎的文件系统API通常提供以下功能: 搜需路径:是含一串路径的字符串,各路径之间以特殊字符(如冒号或分号)分隔,找文件时就会从这些路径进行搜寻。例如在命令行下执行程序&a…...
Wagtail安装运行并结合内网穿透实现公网访问本地网站界面
文章目录 前言1. 安装并运行Wagtail1.1 创建并激活虚拟环境 2. 安装cpolar内网穿透工具3. 实现Wagtail公网访问4. 固定的Wagtail公网地址 正文开始前给大家推荐个网站,前些天发现了一个巨牛的 人工智能学习网站, 通俗易懂,风趣幽默…...
10分钟快速开始SkyWalking结合Springboot项目
10分钟快速开始SkyWalking结合Springboot项目 实习期间,公司让我去学习一下链路追踪如何集成到Springboot项目中。 为此有两个方案: 1.opentelementryjaegerprometheus opentelementry 收集器收集线上的metrics和traces,然后发送给jaeger和p…...
STM32—触摸键
目录 1 、 电路构成及原理图 2 、编写实现代码 3、代码讲解 4、烧录到开发板调试、验证代码 5、检验效果 此笔记基于朗峰 STM32F103 系列全集成开发板的记录。 1 、 电路构成及原理图 触摸键简单的了解就是一次电容的充放电过程。从原理图可以看出,触摸键 …...
python中字典(dict)原理及其操作
原理 Python中的字典(Dictionary)是一种基于哈希表(Hash Table)的实现,提供了高效的键值对(Key-Value Pair)存储和访问机制。了解字典的工作原理有助于更好地理解其性能特性以及为什么在某些情…...
.NET Core Web API实现微服务集群部署
.NET Core Web API实现微服务集群部署 在.NET Core Web API中实现微服务集群部署通常涉及多个步骤,包括服务拆分、容器化、服务注册与发现、负载均衡等。以下是一个简化的步骤指南,用于在.NET Core中构建和部署微服务集群: 服…...
网络安全与信创产业发展:构建数字时代的护城河
✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua,在这里我会分享我的知识和经验。&#x…...
外包干了3个月,技术倒退1年。。。
先说情况,大专毕业,18年通过校招进入湖南某软件公司,干了接近6年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…...
Unity发布webgl获取浏览器的URL
Unity发布webgl获取浏览器的URL Unity发布webgl之后获取浏览器的url 在unity中创建文件夹Plugins,然后添加添加文件UnityGetBrowserURL.jslib var GetUrlFunc {//获取地址栏的URLStringReturnValueFunction: function () {var returnStr window.top.location.hre…...
StarRocks实战——多维分析场景与落地实践
目录 一、OLAP 系统历史背景 1.1 历史背景与痛点 1.2 组件诉求 二、StarRocks 的特点和优势 2.1 极致的查询性能 2.2 丰富的导入方式 2.3 StarRocks 的优势特点 三、多维分析的运用场景 3.1 实时计算场景 / 家长监控中心 3.2 实时更新模型选择 3.2.1 更新模型UNIQU…...
golang 函数式编程库samber/mo使用: Result
golang 函数式编程库samber/mo使用: Result 如果您不了解samber/mo库, 请先阅读上一篇 Option , 这篇讲述结构体Result的使用 Result和Option区别 samber/mo有了Option, 为什么还有Result呢? 我们先看看定义: Opt…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
