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
  • 基于这个变量判断是否还有任务,如果还有,则继续往里面注册回调,没有则退出

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

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

相关文章

Linux学习之vi/vim详细介绍

目录 ​编辑 1. 什么是 vim&#xff1f; 2. vi/vim 的使用 2.1 命令模式 2.2 输入模式 2.3 底线命令模式 3. vi/vim 使用实例 3.1 使用 vi/vim 进入一般模式 3.2 按下 i 进入输入模式(也称为编辑模式)&#xff0c;开始编辑文字 3.3 按下 ESC 按钮回到一般模式…

【Git企业实战开发】Git常用开发流操作总结

【Git企业实战开发】Git常用开发流操作总结 大家好 我是寸铁&#x1f44a; 总结了一篇Git常用开发流操作总结的文章✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 现在刚做项目的伙伴&#xff0c;可能你之前学过git&#xff0c;但是一实战发现不熟悉 没关系&#xff0c;看寸铁这篇…

LLM 模型融合实践指南:低成本构建高性能语言模型

编者按&#xff1a;随着大语言模型技术的快速发展&#xff0c;模型融合成为一种低成本但高性能的模型构建新途径。本文作者 Maxime Labonne 利用 mergekit 库探索了四种模型融合方法&#xff1a;SLERP、TIES、DARE和passthrough。通过配置示例和案例分析&#xff0c;作者详细阐…

Base64 编码 lua

Base64 编码 -- Base64 字符表 local base64_chars { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,…

Docker复习笔记

Centos7安装Docker Docker官网:www.docker.com Docker官网仓库:hub.docker.com Docker文档是比较详细的 安装相关依赖 yum -y install gcc gcc-c yum install -y yum-utils 设置docker镜像仓库 yum-config-manager --add-repo https://download.docker.com/linux/centos/do…

高分SCI绘图必备!你必须要学会的18种Matlab绘图代码与20个绘图技巧(附完整代码)

目录 绘图技巧篇 绘图代码篇 免费完整代码获取​ 今天为大家带来一期18种Matlab绘图代码与20个绘图技巧代码&#xff0c;所有代码完全免费&#xff01; 如果你想发SCI&#xff0c;普通的图已经进入不了审稿人的视线了&#xff0c;非常容易被拒稿。试想&#xff0c;如果一篇…

【b站咸虾米】chapter5_uniapp-API_新课uniapp零基础入门到项目打包(微信小程序/H5/vue/安卓apk)全掌握

课程地址&#xff1a;【新课uniapp零基础入门到项目打包&#xff08;微信小程序/H5/vue/安卓apk&#xff09;全掌握】 https://www.bilibili.com/video/BV1mT411K7nW/?p12&share_sourcecopy_web&vd_sourceb1cb921b73fe3808550eaf2224d1c155 目录 5 API 5.1 页面和路…

【Java程序设计】【C00287】基于Springboot的疫情防控期间某村外出务工人员管理系统(有论文)

基于Springboot的疫情防控期间某村外出务工人员管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的疫情防控期间某村外出务工人员信息管理系统 本系统分为系统功能模块、管理员功能模块、用户功能模块、采集…

两结点之间创建简单的梁单元并进行线性网格划分的方法

进入1D面板->进入bars界面 https://zhuanlan.zhihu.com/p/613163100

【Unity】Unity与安卓交互

问题描述 Unity和安卓手机进行交互&#xff0c;是我们开发游戏中最常见的场景。本教程将从一个简单的例子来演示一下。 本教程需要用到Android Studio2021.1.1 1.Android Studio新建一个工程 2.选择Empty Activity 然后点击Next 3.点击Finish完成创建 4.选择File-New-New Mo…

Linux:Jenkins用户权限和管理

1.下载插件 由于Jenkins的默认权限管理并不是很精细所以我们安装一个插件进行权限的一个管理 插件名称为&#xff1a;Role-based Authorization Strategy 安装完插件我们再去配置一下 进入全局安全配置 选择这个Role-Based Strategy策略然后保存 2.创建角色 我们这里主要使…

Odoo系统安装部署并结合内网穿透实现固定域名访问本地ERP系统

文章目录 前言1. 下载安装Odoo&#xff1a;2. 实现公网访问Odoo本地系统&#xff1a;3. 固定域名访问Odoo本地系统 前言 Odoo是全球流行的开源企业管理套件&#xff0c;是一个一站式全功能ERP及电商平台。 开源性质&#xff1a;Odoo是一个开源的ERP软件&#xff0c;这意味着企…

企微hook框架

https://wwm.lanzoum.com/ipUTp1ot1twh 密码:hvev 免费的企微框架 支持文本消息&#xff0c;图片消息&#xff0c;视频消息&#xff0c;文件消息。 其他可自行下载测试。 有兴趣可以进群交流。720192224 BOOL WxWorkSendData(string data) { WX_GETOBJDATA ob…

[C++]18:set和map的使用

set和map的使用 一.关联式容器&#xff1a;1.简单概念&#xff1a;2.<key , value>--->键值对3.set和map的底层结构&#xff08;平衡搜索树或者红黑树&#xff09; 二.set1.set (排序不重复)1.模板参数&#xff1a;2.set是一个有序存储的容器&#xff1a;3.set中每个数…

Vi/Vim 使用小窍门,如何消除搜索后的关键字高亮

Vim/Vi 基本上是 *nix 世界最受欢迎的编辑器了&#xff0c;不知道为什么&#xff0c;一直以来觉得和 Emacs 比起来&#xff0c;Vim 更加有亲和力。用起来很舒服。 今天就记录一个困扰了我很久的问题。 大家应该都知道&#xff0c;在 Vi 里面如果要搜索某个关键字&#xff0c;…

ChatGPT调教指南 | 咒语指南 | Prompts提示词教程(三)

在人工智能成为我们日常互动中无处不在的一部分的时代&#xff0c;与大型语言模型(llm)有效沟通的能力是无价的。“良好提示的26条原则”为优化与这些复杂系统的交互提供了全面的指导。本指南证明了人类和人工智能之间的微妙关系&#xff0c;强调清晰、专一和结构化的沟通方法。…

vscode输入英文时字体之间的间隔突然变大,似中文

vscode输入英文时字体之间的间隔突然变大&#xff0c;似中文 主要原因&#xff1a; 是由于输入法变成全角模式了。原因可能是不小心按了 shift空格键快捷键造成的。 正常情况&#xff0c;全角就是字母和数字等与汉字占等宽位置的字。 半角就是ASCII方式的字符&#xff0c;在没…

Sora:视频生成模型作为世界模拟器

我们探索了视频数据上生成模型的大规模训练。具体来说&#xff0c;我们在可变持续时间、分辨率和长宽比的视频和图像上联合训练文本条件扩散模型。我们利用了一个在视频和图像潜在码的时空块上操作的变压器架构。我们规模最大的模型 Sora 能够生成一分钟的高保真视频。我们的结…

第十四章 Linux面试题

第十四章 Linux面试题 日志t.log(访问量)&#xff0c; 将各个ip地址截取&#xff0c;并统计出现次数&#xff0c;并按从大到小排序(腾 讯) http://192. 168200.10/index1.html http://192. 168.200. 10/index2.html http:/192. 168 200.20/index1 html http://192. 168 200.30/…

c++学习记录 STL初识—vector存放内置数据类型

#include<iostream> using namespace std; #include<vector> #include<algorithm>//标准算法头文件//容器&#xff1a;vector //算法&#xff1a;for_each //迭代器&#xff1a;vector<int>::iteratorvoid myPrint(int val) {cout << val <&l…