首页 > 其他分享 >Scheduler工作流程

Scheduler工作流程

时间:2024-08-17 18:38:22浏览次数:12  
标签:taskQueue performConcurrentWorkOnRoot 流程 工作 Scheduler workLoop 执行 方法

Scheduler 的目的

React 实现 Scheuler 的目的是想要实现时间切片。

时间切片是指:将长任务拆分成多段,每次执行一小段的任务的操作。

Scheduler 的实现

React 利用 MessageChannel 创建出一个 port 实例,port 实例有两个属性 port1 和 port2。如果在 Scheduler 当中调用 port2.postMessage() 时,浏览器就会调用 port1.onmessage 方法绑定的回调函数然后执行它。绑定的这个函数的函数名是 performWorkUntilDeadline。

performWorkUntilDeadline 函数的主要工作是调用 scheduledHostCallback 方法。而在执行完 scheduledHostCallback 方法时它的执行结果为 true,那么会接着执行port2.postMessage ()。

这样就会继续通过 performWorkUntilDeadline 方法执行 scheduledHostCallback。

而这个 scheduledHostCallback 变量是通过执行 requestHostCallback 方法时赋值的 flushWork 方法。所以 scheduledHostCallback 就是 flushWork。执行 performWorkUntilDeadline 就是执行
flushWork。

scheduleCallback

Scheduler 会向外暴露一个方法: scheduleCallback。这个方法接收两个参数:优先级,回调函数。它的目的就是以什么样的优先级调用一个回调函数。

Scheduler 的优先级

Scheduler 定义了 5 中优先级:ImmediatePriority、UserBlockingPriority、NormalPriority、LowPriority、IdlePriority。优先级分别从高到低。

这些优先级分别对应 -1、250、5000、10000、1073741823(最大 31 位二进制整数)值。

scheduleCallback 的工作流程

调用 scheduleCallback 方法首先会创建 task 对象,包含:callback、priorityLevel、startTime 和 expirationTime。

  • callback 对应第二个参数
  • priorityLevel 对应第一个参数
  • startTime 一般对应当前时间,如果宿主支持 performance 对象则通过 performance.now() 获取,否则将通过 Date.now() 获取
  • expirationTime = startTime + timeout,timeout 对应第一个参数对应的值

所以 Scheduler 中优先级也表示当前回调函数的过期时间。优先级越高就会越快过期,优先级越低就会越慢过期。

taskQueue 和 timerQueue

那么当startTime大于currentTime就表示这个 task 还没有过期,Scheduler 会将这个未过期的任务 push 到 timerQueue 中,timerQueue 就是用来保存未过期任务的队列。

而 startTime 小于等于 currentTime 就表示这个 task 已经过期了,Scheduler 会将这个过期任务 push 到 taskQueue 中,taskQueue 就是用来保存过期任务的队列。

说是队列不够准确,taskQueue 和 timerQueue 都是小顶堆,小顶堆是一颗完全二叉树。堆顶存放的都是最快过期时间的任务。

那么既然有了 taskQueue 就需要函数来执行它。

这个任务就是 workLoop 方法,而 workLoop 方法是通过 flushWork 调用的, 即上面提到过的 performWorkUntilDeadline。

所以这样就捋出了一条完整的流水线:先执行 port2.postMessage -> performWorkUntilDeadline -> flushWork -> workLoop -> 执行 taskQueue -> callback。

workLoop 的工作流程是先调用advanceTimers从 timerQueue 中取出过期任务放到 taskQueue 中。然后取出 taskQueue 中堆顶的任务执行它的 callback 属性,即传入的回调函数。

这个回调函数通常指 performConcurrentWorkOnRoot,即并发模式下 render 阶段的入口函数。

而时间切片的特性就体现在了这里:将同步的更新变为异步可中断的更新。

shouldYield

通过performConcurrentWorkOnRoot方法会调用renderRootConcurrent,然后调用workLoopConcurrent。

在 workLoopConcurrent 方法中会通过 while 循环执行 performUnitOfWork 方法。while 条件语句当中会通过 shouldYield 方法执行结果判断是否继续执行 performUnitOfWork 方法。

shouldYield 正是通过 Scheduler 中提供的方法。目的是判断当前帧是否还有剩余时间来执行浏览器的渲染工作。如果有剩余时间 shouldYield 会返回 false,没有剩余时间会返回 true。

当返回 true 时就会暂停执行 performUnitOfWork 方法,实现暂停 render 阶段的执行。

shouldYield的实现原理就是判断 getCurrentTime() >= deadline ,deadline 在执行 performWorkUntilDeadline 时会被赋值 currentTime + yieldInterval(yieldInterval = 5)。

所以从这里可以看出 Scheduler 为 render 阶段的执行时间预留的时间就是 5ms,如果大于 5ms 就会暂停 performUnitOfWork 方法的执行。等到下一帧再继续执行 performUnitOfWork 方法的 render 阶段。

任务的暂停到恢复

当 performUnitOfWork 方法被中断后又是如何恢复执行的呢?

在 workLoop 方法中执行 callback 后,即 performConcurrentWorkOnRoot 方法,如果 performUnitOfWork 被中断了,则 performConcurrentWorkOnRoot 方法会将自己作为执行结果再return出去 。如果 performUnitOfWork 没有被中断则会 return null。所以 workLoop 会判断当前 callback 是否有返回值。如果有返回值则将该返回值再赋值给 callback 属性。如果没有返回值则将该回调函数对应的 task 从 taskQueue 中删除。

所以到这里应该明白了当前帧被中断的 performConcurrentWorkOnRoot方法,将在下一帧中等待 workLoop 方法的执行。

直到这个 performConcurrentWorkOnRoot 方法执行结束。否则 performConcurrentWorkOnRoot 对应的 task 将一直保留在 taskQueue 中等待 workLoop 方法的执行。

workLoop 方法的执行结果会根据 taskQueue 中是否还有过期的任务,如果还有过期任务则会 return true,否则将 return false。

因为 workLoop 方法是在 flushWork 方法中执行的。所以 flushWork 也会将 workLoop 方法的执行结果 return 出去当作自己的执行结果。

在 performWorkUntilDeadline 中会对 flushWork 方法的执行结果做判断。如果执行结果是 true,那么将继续执行 port2.postMessage。否则将 scheduledHostCallback置为空。

Scheduler 完整的执行流程

scheduleCallback(normalPriority, performConcurrentWorkOnRoot) ->
requestHostCallback ->
port2.postMessage ->
performWorkUntilDeadline ->
scheduledHostCallback ->
flushWork ->
workLoop ->
callback(performConcurrentWorkOnRoot)->
renderRootConcurrent ->
workLoopConcurrent ->
shouldYield 返回 true ->
中断 performUnitOfWork ->
performConcurrentWorkOnRoot 返回 performConcurrentWorkOnRoot.bind ->
workLoop 返回 true ->
flushWork 返回 true ->
performWorkUntilDeadline ->
port2.postMessage ->
... 重复上述流程 直到 performConcurrentWorkOnRoot 结束完成 返回 null ->
重置 scheduledHostCallback为 null ->
结束

思考

React 使用 MessageChannel 来实现时间切片特性的可能原因:MessageChannel 调度的回调函数是宏任务,这样当该回调函数执行结束之后可以将主线程的控制权交还给浏览器,方便浏览器执行渲染工作。

不用微任务的原因可能也是因为无法交还主线程的控制权,因为当前如果产生微任务的话,将一直执行微任务,直到微任务全部执行完。这样浏览器就一直没办法执行渲染的工作了。

不使用setTimeout的原因是因为 setTimeout 调用回调函数是有最小延迟的时间,会浪费宝贵的执行时间。

但是在 Scheduler 中也会判断,如果当前宿主环境不支持 MessageChannel,则会改为使用 setTimeout 。

标签:taskQueue,performConcurrentWorkOnRoot,流程,工作,Scheduler,workLoop,执行,方法
From: https://www.cnblogs.com/rocenjs/p/18364804

相关文章

  • JAVA执行流程
    基本流程Java程序的运行必须经过编写、编译和运行3个步骤:1、编写:是指在Java开发环境中进行程序代码的输入,最终形成后缀名为.java的Java源文件。2、编译:是指使用Java编译器对源文件进行错误排査的过程,编译后将生成后缀名为.class的字节码文件,不像C语言那样生成可执......
  • 网络监控管理系统是什么?一站式网络监控,360°无死角管理,让运维工作事半功倍!
    在信息化高速发展的今天,企业的网络环境日益复杂,数据安全与运维效率成为了企业管理中的重中之重。为了应对这一挑战,安企神网络监控管理系统应运而生,它以一站式、360°无死角的管理策略,为企业的网络运维工作带来了革命性的变革,让运维工作事半功倍。一、什么是网络监控管理系统?......
  • DolphinScheduler集群部署问题(趟坑)总结
    目录官方文档官方项目地址问题解决官方文档DolphinScheduler|文档中心(apache.org)官方项目地址部署及使用过程中的问题可以参见项目Issue:Issues·apache/dolphinscheduler·GitHubGitHub-apache/dolphinschedulerat3.2.2-release问题解决1、JVM在运......
  • 误闯机器学习(第一关-概念和流程)
    以下内容,皆为原创,实属不易,请各位帅锅,镁铝点点赞赞和关注吧!好戏开场了。一.什么是机器学习        机器学习就是从数据中自动分析获取模型(总结出的数据),并训练模型,去预测数据。    内心独白:就好比我们人从日常生活中,归纳总结得出经验。利用总结的经验去得出......
  • 面试题:在Java中,线程之间的通信主要通过哪几种方式实现?并简述其中一种方式的基本工作原
    面试题:在Java中,线程之间的通信主要通过哪几种方式实现?并简述其中一种方式的基本工作原理。请注意,除了直接回答此问题外,我们还为您准备了更多深入的学习资源和面试技巧。想要了解更多关于Java线程通信、优化简历、模拟面试、企业项目源码、大厂高并发面试题、项目场景题、算法......
  • h5直播源码,用户登录流程及权限校验
    h5直播源码,用户登录流程及权限校验今天我们来看一下用户登录的流程前端部分 以一个后台管理系统登录为例:登录篇1.用户输入账号和密码点击登录传给服务器用户名和密码2.服务器验证成功后给客户端传递一个token,并且把这个token存在cookies中,这样下次再向服务器发请......
  • 【本地+在线】Comfyui的基本工作流的搭建----文生图+图生图
    一.(本地使用comfyui)基本模块的了解1.1这是初始界面1.2搭建一个基本的工作流(如果使用的是秋叶大佬的包,每次进入会自动出现该工作流)1.2.1加载器和取样器:加载器,鼠标右键,点击新建节点,按下图操作,出现加载器取样器,鼠标右键,然后按下图操作可以看到如图结果:我们将“模型“连接......
  • 【网络】UDP回显服务器和客户端的构造,以及连接流程
    回显服务器(EchoServer)最简单的客户端服务器程序,不涉及到业务流程,只是对与API的用法做演示客户端发送什么样的请求,服务器就返回什么样的响应,没有任何业务逻辑,没有进行任何计算或者处理0.构造方法网络编程必须要使用网卡,就需要用到Socket对象创建一个DatagramS......
  • tortoisegit下载及其使用流程
    下载    官方下载链接:Download–TortoiseGit–WindowsShellInterfacetoGit    选择适合自己的电脑位数的版本:一般64的兼容32的按照就不介绍了怎么开心怎么来,本篇暂时为了支持一位粉丝的疑惑安装的话没有特殊配置暂不介绍,一路安装即可叮!这里停一......
  • git command 工作中常用命令备忘录
    模拟目前工作流程在gitlabfork需要开发的项目到自己仓库分配一个工作任务(feature、improvment、bug)本地从个人仓库克隆项目gitclonehttp://mylocal/group/project本地添加对于远端项目gitremoteaddupstreamhttp://dev.xxx.io/group/project基于远端仓库切出本......