React18源码: schedule任务调度messageChannel

2023前端面试复盘:快手三面+HR面完整记录与避坑指南 前端面试的核心不仅是对知识点的记忆,更是对原理理解深度与工程实践能力的综合检验。从事件循环、浏览器缓存到React Fiber架构与并发模式,再到性能优化、工程化与系统设计,大厂面试官越来越倾向于围绕候选人的项目经历层层追问,考察其是否具备闭环的问题拆解能力。深入理解框架设计原理、掌握虚拟滚动与代码分割等性能优化手段、熟悉微前端与监控平台等工程化实践,已成为前端开发者应对高阶面试的关键竞争力。在求职窗口期,系统性地进行项目复盘、算法题训练和模拟面试,是提升面试表现的有效路径。本文以2023年快手前端面试为样 阅读详情

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();
        // 更新 deadline
        deadline = currentTime + yieldInterval;
        // 执行 callback
        scheduledHostCallback(hasTimeRemaining, currentTime);
      } else {
        isMessageLoopRunning = false;
      };
    };
    
    const channel = new MessageChannel();
    const port = channel.port2;
    channel.port1.onmessage = performWorkUntilDeadline;
    
    // 请求回调
    requestHostCallback = function(callback) {
      // 1.保存callback
      scheduledHostCallback = 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 ESLint
        console['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 framerate
        yieldInterval = 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
  • 基于这个变量判断是否还有任务,如果还有,则继续往里面注册回调,没有则退出
【React】版本18 代码遨游(十)调度器 scheduler 调度器 文章目录调度器import内容变量方法*advanceTimers*(currentTime)*flushWork*(hasTimeRemaining, initialTime)*workLoop*(hasTimeRemaining, initialTime)*requestHostTimeout*(callback, ms)*handleTimeout*(currentTime)*unstable_runWithPriority*(priorityLevel, eventHandler)*unst 阅读详情

相关推荐

react-scheduler:它是使用React编写的调度程序。

Create React App入门 该项目是通过引导的。 可用脚本 在项目目录中,可以运行: yarn start 在开发模式下运行应用程序。 打开在浏览器中查看它。 如果您进行编辑,则页面将重新加载。 您还将在控制台中看到任何棉绒错误。 yarn test 在交互式监视模式下启动测试运行器。 有关更多信息,请参见关于的部分。 yarn build 构建生产到应用程序build文件夹。 它在生产模式下正确捆绑了React,并优化了构建以获得最佳性能。 生成被最小化,并且文件名包括哈希值。 您的应用已准备好进行部署! 有关更多信息,请参见关于的部分。 yarn eject 注意:这是单向操作。 eject ,您将无法返回! 如果您对构建工具和配置选择不满意,则可以随时eject 。 此命令将从您的项目中删除单个生成依赖项。 相反,它将所有配置文件和传递性依赖项(webpa

【React源码】(七)React 调度原理(scheduler)

本节主要分析了scheduler包中调度原理, 也就是React两大工作循环中的任务调度循环. 并介绍了时间切片和可中断渲染等特性在任务调度循环中的实现.scheduler包是React运行时的心脏, 为了提升调度性能, 注册task之前, 在包中做了节流和防抖等措施.

weixin_44828588的博客 1741

树莓派驱动DLPDLCR230NPEVM+framebuffer显示图片

DLPDLCR230NPEVM DLP® LightCrafter™ Display 230NP 是一个易于使用的紧凑型即插即用评估平台,适用于消费类产品、工业、医疗和物联网 (IoT) 市场中的各种超便携显示应用。此评估模块 (EVM) 采用 DLP230NP 芯片组,该芯片组由DLP230NP.23 1080p DMD、DLPC3436显示控制器和DLPA2005PMIC/LED 驱动器组成。此 EVM 外形小巧,配备生产就绪型光学引擎以及支持 18 位 RGB 并行视频接口...

L_Y000的博客 2621

React 的调度系统 Scheduler

大家好,我是前端西瓜哥。今天来学习 React 的调度系统 Scheduler。React 使用了全新的 Fiber 架构,将原本需要一次性递归找出所有的改变,并一次性更新真实 DOM 的流程,改成通过时间分片,先分成一个个小的异步任务在空闲时间找出改变,最后一次性更新 DOM。这里需要使用调度器,在浏览器空闲的时候去做这些异步小任务。做这个调度工作的在 React 中叫做 Scheduler(调度器)模块。其实浏览器是提供一个 requestIdleCallback 的方法,让我们可以在浏览器空闲的时去调

fe_watermelon的博客 1768

EEGLAB数据预处理基本流程GUI实操指南

按钮,会出现如上图所示的长条形对话框,方框里面是所有电极的名称,这时将需要的剔除的电极选择上,如上图,我选择了 VEOG这个电极(该电极表示是垂直眼电),然后点“OK”,在弹出的对话框中自行确定是否需要修改命名。坏导是指在数据采集时,由于各种原因(如,电极本身问题或阻抗不好等)导致数据记录有问题,但是在后期又特别想要该通道的数据,那么就可以利用插值的方法进行——利用该导联周边的几个电极点的均值作为该导的数据。上图的图是通过IClabel的工具箱进行自动判断的,可以帮助自动识别出哪些是Eye的成分。

fdgdf5535的博客 6398

智能车竞赛飞檐走壁组立体赛道电磁引导线设计与实现

本文深入解析了智能车竞赛飞檐走壁组立体赛道电磁引导线的核心设计与实现。针对垂直面、圆筒、跷跷板等立体元素,详细阐述了电磁线规格参数选择、三维空间铺设技巧及磁场调试方法,旨在帮助参赛队伍打造稳定可靠的导航系统,提升车模在复杂立体赛道上的通过率与稳定性。

bert9linguist的博客 282

《深入理解react》之调度引擎——Scheduler

实际上 Scheduler 中一共维护了两个队列,本文并没有提到关于timerQueue的相关信息,那是因为在 react 的调度流程中基本不会涉及到timerQueue所以如果单纯理解 react 其实以上的知识已经足够,出于篇幅原因,timerQueue 相关的信息我会在后续的文章中进行详细分析。如果你喜欢这样的行文风格,可以关注我的《深入理解react》专栏,持续更新中…当前时间startTime。

weixin_50786692的博客 1997

大模型抽取知识图谱三元组的可行性分析

通过结合传统信息抽取模型与大语言模型的混合架构,可高效完成从学术文献到知识图谱三元组的全流程构建。分阶段优化:传统模型负责粗粒度抽取,大模型负责细粒度修正。灵活提示设计:通过少样本学习引导大模型理解领域本体。严格质量控制:结合规则引擎和人工校验,确保三元组准确性。该方案可显著提升知识图谱构建效率,适用于学术研究、企业知识库等场景。

qq_20647053的博客 1067

【React Scheduler源码第二篇】React Scheduler用法详解

React Scheduler 基础用法,高优先级任务如何插队,长任务如何切片,任务切片如何中途取消,任务过期等基础知识,为后续手写scheduler源码奠定坚实的基础

lzc的博客 853

uniapp - 热更新提示:WGT安装包中manifest.json文件不存在 | unexpected EOF!报错详细解决,完美搞定WGT安装包中WWW目录下manifest.json不存在问题

uniapp,安卓android,苹果ios,热更新,热更新code:-1202报错,,WGT热更新报错,uniapp热更新wgt出现报错manifest.json文件不存,uniapp安卓苹果软件热更新时出现错误unexpected EOF!如何解决,怎么解决热更新wgt报错,app新版本下载安装报错WGT安装包中manifest.json文件不存在,WGT安装包中WWW目录下manifest.json不存在,uniapp热更新报错安装失败[-1201]:WGT/WGTU文件格式错误,uniapp-wgt

✅ 精选推荐文章 1万+

SQL进阶技巧:数据预处理如何对数据进行分桶【分箱】?

本文详细介绍了数据分析中常见的几种分桶方式:基于业务规则的分桶、等距分桶及等频分桶等,针对每种分桶方式给出了SQL实现

石榴姐yyds 4021

React 第三十六章 Scheduler 任务调度

用于在 React 应用中进行任务调度。它可以帮助开发人员在处理复杂的任务和操作时更好地管理和优化性能。关于 Scheduler 在React 如何渲染的可以参考下面我们根据流程图先简单的了解 Scheduler 的调度过程Scheduler 维护两个队列,分别存放普通任务和延时任务当接收的是普通任务时,会加入普通任务队列,然后执行。根据环境创建宏任务(主要创建的就是),然后执行。该方法实际上主要就是在调用。

aXin_li的博客 1592

自监督学习原理与代码实战案例讲解

自监督学习原理与代码实战案例讲解 作者:禅与计算机程序设计艺术 1. 背景介绍 1.1 自监督学习的起源与发展 1.1.1 监督学习的局限性

AI天才研究院 624

深入分析React-Scheduler原理

关键词:react react-scheduler scheduler 时间切片 任务调度 workLoop。

xiaofeng123aazz的博客 592

用 CL_ABAP_ZIP 在 ABAP 里打包任意文件:从前端多选到 ZIP 交付的一条龙实践

本文介绍了在SAP ABAP中实现文件打包交付的完整解决方案。文章首先区分了ZIP和GZIP的不同用途:ZIP用于多文件归档,GZIP用于单数据流压缩。核心流程包括四个步骤:文件选择、二进制上传、内存打包和ZIP输出,并提供了关键对象与函数的速查表。针对实际项目中常见的乱码、大文件处理等问题给出了解决方案,最后展示了一个完整的可运行示例代码,涵盖了从文件选择到下载的全流程实现。该方案适用于财务、质量、运维等多种业务场景,能够有效解决多文件交付的最后一公里问题。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 219

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

react scheduler任务循环调度源码解析

主要通过requestHostCallback注册任务,任务是flushWork,通过MessageChannel的宏任务来执行,flushWork主要调用workLoop进行循环执行taskQueue中的任务,若一帧执行完还有剩余任务返回true给到requestHostCallback中的MessageChannel,然后MessageChannel将任务放到下一次的宏任务中去执行,实现分帧的调用 对于任务的优先级,即通过SchedulerPriority转换成对应的时间,累加到注册该任务时的时间...

weixin_43294560的博客 1623

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

从零实现React Scheduler调度器

本文介绍了React团队开发的Scheduler任务调度器,通过生动类比(如"厕所排队")解释其核心原理。Scheduler采用五级优先级系统(ImmediatePriority到IdlePriority),使用最小堆管理任务队列,实现时间切片(默认5ms)调度机制。核心功能包括:优先级任务调度、任务中断/恢复、主线程让出等。文章从零实现调度器,包含14个模块:优先级定义、最小堆、时间工具、状态管理、工作循环等,完整还原了React Scheduler的核心逻辑。该调度器能有效解决前端应

2301_80723943的博客 1109

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

requestAnimationFrame 神奇的动画效果

requestAnimationFrame: 相当一部分的浏览器的显示频率是16.7ms,显示器16.7ms刷新间隔之前发生了其他绘制请求(setTimeout),导致所有第三帧丢失,继而导致动画断续显示(堵车的感觉),这就是过度绘制带来的问题。不仅如此,这种计时器频率的降低也会对电池使用寿命造成负面影响,并会降低其他应用的性能。这也是为何setTimeout的定时器值推荐最小使用16...

deqg33573的博客 348

React16源码: React中的schedule调度整体流程

React Fiber Scheduler 是 react16 最核心的一部分,这块在这个包中这个包的核心是 fiber reconciler,也即是 fiber 结构fiber的结构帮助我们把react整个树的应用,更新的流程,能够拆成每一个fibrer对象为单元的一个更新的流程这种单元的形式把更新拆分出来之后,给每个不同的任务提供一个优先级,以及我们在更新的过程当中,可以中断因为我们记录更新到了哪一个单元,中断了之后,可以过一会儿再回过头来,继续从这个单元开始,继续之前没有做完的更新。

Wang的专栏 1604

【React源码11】深入学习React 源码实现——调度器(Scheduler)底层实现

React调度器(Scheduler)是React实现并发模式的核心机制,它通过优先级调度和时间切片技术优化渲染性能。本文详细解析了Scheduler的设计原理

silverclayz的技术分享 1129

【React架构 - Scheduler中的MessageChannel】

【React架构 - Scheduler中的MessageChannel】

weixin_44273311的博客 2085

React Scheduler 时间分片为什么选择使用 MessageChannel 实现

点击上方前端瓶子君,关注公众号回复算法,加入前端编程面试算法每日一题群来源:MoonBallhttps://juejin.cn/post/6953804914715803678本文包括:...

我本可以容忍阳光,如果我不曾见过太阳,然而阳光已使我荒凉,成为更新的荒凉。 2807

React18源码: task任务调度和时间分片

创建任务之后,最后请求调度 requestHostCallback(flushwork)(创建任务源码中的第5步)现在再次回到 react-reconciler包中,在调度过程中的关键路径中,还需要理解一些细节。1.在task注册完成之后,会设置fiberRoot对象上的属性,代表现在已经处于调度进行中。在 Renconciler 运行流程中总结的4个阶段中,注册调度任务属于第2个阶段。调度的目的是为了消费任务,接下来就具体分析任务队列是如何管理与实现的。这2大特性的实现,都集中于这个while循环。

Wang的专栏 1776

五、为什么React中选择MessageChannel来创建任务

MessageChannel

weixin_43854624的博客 753

JAVA Reactor学习--流的异步处理

区别是publishOn会让之后的操作在Scheduler提供的线程中执行,subscribeOn会让之前的操作在Scheduler提供的线程中执行。在Reactor中,提供了多种Sxheduler(类似于线程池,不过是有Reactor管理的)的实现,在Schedulers中提供了多种工厂方法,去获取。这种异步的本质,是将那些阻塞的方法,统一交给Reactor放到其他线程里面管理,以至于,不阻塞主线程的执行,在阿里的代码规范插件中,如果你显示的订阅流,但是没有使用调度器,会出现一下提示。

weixin_74165435的博客 483
上一篇: React18源码: React中的LanePriority和SchedulerPriority
下一篇: React18源码: task任务调度和时间分片
Wang's Blog
博客等级 码龄12年 7434粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值