当前位置:首页 > 科技  > 软件

高端操作:把 React Scheduler 掏出来单独用

来源: 责编: 时间:2024-03-22 08:54:02 265观看
导读我们知道,Scheduler 是 React 提供的底层调度器。但是这个调度器具体是如何用的,可能大部分人都不太清楚了,好在 React 把内部的模块封装得都相对独立,因此,我们可以想个办法,单独把他的 Scheduler 或者 Reconciler 单独掏

ueY28资讯网——每日最新资讯28at.com

我们知道,Scheduler 是 React 提供的底层调度器。但是这个调度器具体是如何用的,可能大部分人都不太清楚了,好在 React 把内部的模块封装得都相对独立,因此,我们可以想个办法,单独把他的 Scheduler 或者 Reconciler 单独掏出来用。ueY28资讯网——每日最新资讯28at.com

一、怎么掏

在 React 的 github 仓库中,找到如下路径的文件:./packages/scheduler/src。ueY28资讯网——每日最新资讯28at.com

ueY28资讯网——每日最新资讯28at.com

这里就是 Scheduler 的全部代码,如图所示,我们可以在 forks 目录中,找到 Scheduler.js,这就是我们的目标文件,他引用了外部的几个小模块的内容。ueY28资讯网——每日最新资讯28at.com

// packages/scheduler/src/forks/Scheduler.jsimport type {PriorityLevel} from '../SchedulerPriorities';import {  enableSchedulerDebugging,  enableProfiling,  enableIsInputPending,  enableIsInputPendingContinuous,  frameYieldMs,  continuousYieldMs,  maxYieldMs,  userBlockingPriorityTimeout,  lowPriorityTimeout,  normalPriorityTimeout,} from '../SchedulerFeatureFlags';import {push, pop, peek} from '../SchedulerMinHeap';// TODO: Use symbols?import {  ImmediatePriority,  UserBlockingPriority,  NormalPriority,  LowPriority,  IdlePriority,} from '../SchedulerPriorities';import {  markTaskRun,  markTaskYield,  markTaskCompleted,  markTaskCanceled,  markTaskErrored,  markSchedulerSuspended,  markSchedulerUnsuspended,  markTaskStart,  stopLoggingProfilingEvents,  startLoggingProfilingEvents,} from '../SchedulerProfiling';export type Callback = boolean => ?Callback;

这里需要注意的是,从 github 上掏出来的代码不是用 TS 写的,而是用 flow 写的,因此这里部分语法可能会报错,需要我们要自己稍作调整才能直接使用,不过改动不大。ueY28资讯网——每日最新资讯28at.com

SchedulerFeatureFlags.js 的代码非常简单,就是定义了一些状态来区分不同的执行阶段。ueY28资讯网——每日最新资讯28at.com

/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow strict */export const enableSchedulerDebugging = false;export const enableIsInputPending = false;export const enableProfiling = false;export const enableIsInputPendingContinuous = false;export const frameYieldMs = 5;export const continuousYieldMs = 50;export const maxYieldMs = 300;export const userBlockingPriorityTimeout = 250;export const normalPriorityTimeout = 5000;export const lowPriorityTimeout = 10000;

SchedulerMinHeap.js 封装了几个小顶堆的操作方法,用于优先级队列的任务管理,因此常用的操作就是 pop、push、peek。ueY28资讯网——每日最新资讯28at.com

SchedulerPriorities.js 定义了几个优先级的常量。ueY28资讯网——每日最新资讯28at.com

/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow strict */export type PriorityLevel = 0 | 1 | 2 | 3 | 4 | 5;// TODO: Use symbols?export const NoPriority = 0;export const ImmediatePriority = 1;export const UserBlockingPriority = 2;export const NormalPriority = 3;export const LowPriority = 4;export const IdlePriority = 5;

SchedulerProfiling.js 是用来分析性能的,我们在调试的时候可以用一下。一般来说都会将其关掉。ueY28资讯网——每日最新资讯28at.com

直接把这些文件复制出来,整理好,就能单独使用了。我们可以看一下 Scheduler.js 返回了什么方法。ueY28资讯网——每日最新资讯28at.com

export {  ImmediatePriority as unstable_ImmediatePriority,  UserBlockingPriority as unstable_UserBlockingPriority,  NormalPriority as unstable_NormalPriority,  IdlePriority as unstable_IdlePriority,  LowPriority as unstable_LowPriority,  unstable_runWithPriority,  unstable_next,  unstable_scheduleCallback,  unstable_cancelCallback,  unstable_wrapCallback,  unstable_getCurrentPriorityLevel,  shouldYieldToHost as unstable_shouldYield,  requestPaint as unstable_requestPaint,  unstable_continueExecution,  unstable_pauseExecution,  unstable_getFirstCallbackNode,  getCurrentTime as unstable_now,  forceFrameRate as unstable_forceFrameRate,};

我们可以在源码中去明确这些方法的具体使用方式,然后根据你的需要选择使用即可。ueY28资讯网——每日最新资讯28at.com

二、语法介绍

我们可以使用 unstable_scheduleCallback 来调度任务,这个方法接收三个参数。ueY28资讯网——每日最新资讯28at.com

function unstable_scheduleCallback(  priorityLevel: PriorityLevel,  callback: Callback,  options?: {delay: number},)

priorityLevel 需要的参数我们在上面已经定义好的,数字越小,优先级越高。ueY28资讯网——每日最新资讯28at.com

callback 就是我们需要被调度的任务。ueY28资讯网——每日最新资讯28at.com

options 中,我们可以传入 delay,来进一步降低任务执行的优先级,表示延迟任务。他会进入到 timerQueue 队列而无法直接执行,只有在特定时机移入到了 taskQueue 中之后才会被执行。ueY28资讯网——每日最新资讯28at.com

unstable_scheduleCallback 返回一个 Task 对象,我们可以在源码中看到这个对象大概长这样。ueY28资讯网——每日最新资讯28at.com

var newTask: Task = {  id: taskIdCounter++,  callback,  priorityLevel,  startTime,  expirationTime,  sortIndex: -1,};

unstable_cancelCallback 可以取消正在调度的任务,在源码内部内容,它通过重置 task.callback = null 来取消。ueY28资讯网——每日最新资讯28at.com

OK,了解了基本用法之后,我们就可以来使用它调度任务了。ueY28资讯网——每日最新资讯28at.com

三、使用

想同优先级

想想如下代码输出顺序如何?ueY28资讯网——每日最新资讯28at.com

unstable_scheduleCallback(NormalPriority, () => {  console.log(1)})unstable_scheduleCallback(NormalPriority, () => {  console.log(2)})unstable_scheduleCallback(NormalPriority, () => {  console.log(3)})unstable_scheduleCallback(NormalPriority, () => {  console.log(4)})// 输出顺序:1, 2, 3, 4

由于他们优先级相同,所以会按照任务创建的先后顺序来确定谁的优先级更高。因此,先创建的先执行。ueY28资讯网——每日最新资讯28at.com

不同优先级

现在我们调整一下优先级,思考一下代码输出顺序如何。ueY28资讯网——每日最新资讯28at.com

unstable_scheduleCallback(LowPriority, () => {  console.log(1)})unstable_scheduleCallback(NormalPriority, () => {  console.log(2)})unstable_scheduleCallback(ImmediatePriority, () => {  console.log(3)})unstable_scheduleCallback(NormalPriority, () => {  console.log(4)})// 输出结果:3,2,4,1

此时优先级不同,则优先级越高的先执行。ueY28资讯网——每日最新资讯28at.com

任务是否超时

我们在创建任务时,会给任务添加一个 expirationTime 字段来表示任务执行时,是否超时。在回调函数中,可以接收一个参数来标记超时状态。ueY28资讯网——每日最新资讯28at.com

unstable_scheduleCallback(NormalPriority, (isTimeout) => {  console.log(4)  console.log(isTimeout)})

他的判断标准如下:ueY28资讯网——每日最新资讯28at.com

const didUserCallbackTimeout = currentTask.expirationTime <= currentTime;

expirationTime 的计算规则如下:ueY28资讯网——每日最新资讯28at.com

var timeout;switch (priorityLevel) {  case ImmediatePriority:    // Times out immediately    timeout = -1;    break;  case UserBlockingPriority:    // Eventually times out    timeout = userBlockingPriorityTimeout;    break;  case IdlePriority:    // Never times out    timeout = maxSigned31BitInt;    break;  case LowPriority:    // Eventually times out    timeout = lowPriorityTimeout;    break;  case NormalPriority:  default:    // Eventually times out    timeout = normalPriorityTimeout;    break;}var expirationTime = startTime + timeout;

上面案例通常情况下会返回 false,但是我们可以在主线程中执行一下耗时任务,让其无法在超时时间以内执行。NormalPriority 优先级的超时时间至少是 5000ms。ueY28资讯网——每日最新资讯28at.com

sunstable_scheduleCallback(NormalPriority, (isTimeout) => {  console.log(4)  console.log(isTimeout) // false})const currentTime = performance.now()while(performance.now() - currentTime < 5000) {}unstable_scheduleCallback(NormalPriority, (isTimeout) => {  console.log(4)  console.log(isTimeout) // true,执行时已经超时})const currentTime = performance.now()while(performance.now() - currentTime < 5000) {}

再来看一个例子:ueY28资讯网——每日最新资讯28at.com

unstable_scheduleCallback(UserBlockingPriority, (isTimeout) => {  console.log(2)  console.log(isTimeout) // true})unstable_scheduleCallback(ImmediatePriority, (isTimeout) => {  console.log(3)  const currentTime = performance.now()  while(performance.now() - currentTime < 100) {}  console.log(isTimeout) // true})unstable_scheduleCallback(NormalPriority, (isTimeout) => {  console.log(4)  console.log(isTimeout) // false})const currentTime = performance.now()while(performance.now() - currentTime < 200) {}

此时主线程卡住 200ms,因此 3 ImmediatePriority 超时。此时 3 执行,又卡了 100ms,那么 2 UserBlockingPriority 对应 250ms 延迟时间,此时也超时了。ueY28资讯网——每日最新资讯28at.com

任务中断

此时我们要声明一个任务来遍历一个数组,数组中的每一项的执行时间都比较长,声明数组如下:ueY28资讯网——每日最新资讯28at.com

const tasks: any[] = [  ["1", 3],  ["2", 3],  ["3", 5],  ["4", 7],  ["5", 9],];

我们可以结合 unstable_shouldYield 来判断当前执行时间是否过长,然后以中断遍历过程的方式,中断任务的执行。ueY28资讯网——每日最新资讯28at.com

function node_task() {  console.log('开始执行任务')  var task  while(task = tasks.shift()) {    var now = performance.now()    // 卡住执行    while(performance.now() - now < task[1]) {}    console.log(task[0], '小任务执行完毕')    if (unstable_shouldYield()) {      console.log('执行超过了 5ms,中断执行')      return node_task    }  }}

unstable_shouldYield 是超过 5ms 就需要中断一次,此时我们发现,任务 1 与 任务 2 加起来超过了 5ms,因此 2 执行完之后,会中断一次。,后面的每个任务都比较长,因此每个任务执行完都会中断一次,所以总共会中断 4 次。ueY28资讯网——每日最新资讯28at.com

调度之后,我们看看打印结果:ueY28资讯网——每日最新资讯28at.com

unstable_scheduleCallback(NormalPriority, node_task);

ueY28资讯网——每日最新资讯28at.com

完整的符合预期。ueY28资讯网——每日最新资讯28at.com

高优先级插队

我们只需要把上面的案例稍作调整,就能做到高优先级插队。在 node_task 的执行过程中,我们利用 setTimeout 调度一个更高优先级的任务。ueY28资讯网——每日最新资讯28at.com

const tasks: any[] = [  ["1", 3],  ["2", 3],  ["3", 5],  ["4", 7],  ["5", 9],];function node_task() {  console.log('--开始执行任务--')  var task  while(task = tasks.shift()) {    var now = performance.now()    // 卡住执行    while(performance.now() - now < task[1]) {}    console.log(task[0], '小任务执行完毕')    if (unstable_shouldYield()) {      console.log('执行超过了 5ms,中断执行')      return node_task    }  }}unstable_scheduleCallback(NormalPriority, node_task);+ setTimeout(() => {+   unstable_scheduleCallback(ImmediatePriority, () => {+     console.log('我是高优先级插队')+  });+ }, 10)

执行结果如下,插队成功。ueY28资讯网——每日最新资讯28at.com

ueY28资讯网——每日最新资讯28at.com

四、总结

我们可以利用这一套优先级队列的调度,解决实践中的需求。例如,在开发弹幕功能的时候,我们会想办法优先让自己发的弹幕先弹出来。或者在消息弹窗提示时,优先弹出错误警告等。ueY28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-78500-0.html高端操作:把 React Scheduler 掏出来单独用

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 定制JSON转换:探索.NET Core中JsonSerializerOptions的秘密

下一篇: 面试官:说说零拷贝的实现原理?

标签:
  • 热门焦点
  • 小米官宣:2023年上半年出货量中国第一!

    今日早间,小米电视官方微博带来消息,称2023年小米电视上半年出货量达到了中国第一,同时还表示小米电视的巨屏风暴即将开始。“公布一个好消息2023年#小米电视上半年出货量中国
  • 7月安卓手机性能榜:红魔8S Pro再夺榜首

    7月份的手机市场风平浪静,除了红魔和努比亚带来了两款搭载骁龙8Gen2领先版处理器的新机之外,别的也想不到有什么新品了,这也正常,通常6月7月都是手机厂商修整的时间,进入8月份之
  • 0糖0卡0脂 旭日森林仙草乌龙茶优惠:15瓶到手29元

    旭日森林无糖仙草乌龙茶510ml*15瓶平时要卖为79.9元,今日下单领取50元优惠券,到手价为29.9元。产品规格:0糖0卡0脂,添加草本仙草汁,清凉爽口,富含茶多酚,保留
  • 多线程开发带来的问题与解决方法

    使用多线程主要会带来以下几个问题:(一)线程安全问题  线程安全问题指的是在某一线程从开始访问到结束访问某一数据期间,该数据被其他的线程所修改,那么对于当前线程而言,该线程
  • 一篇文章带你了解 CSS 属性选择器

    属性选择器对带有指定属性的 HTML 元素设置样式。可以为拥有指定属性的 HTML 元素设置样式,而不仅限于 class 和 id 属性。一、了解属性选择器CSS属性选择器提供了一种简单而
  • 一个注解实现接口幂等,这样才优雅!

    场景码猿慢病云管理系统中其实高并发的场景不是很多,没有必要每个接口都去考虑并发高的场景,比如添加住院患者的这个接口,具体的业务代码就不贴了,业务伪代码如下:图片上述代码有
  • 小红书1周涨粉49W+,我总结了小白可以用的N条涨粉笔记

    作者:黄河懂运营一条性教育视频,被54万人&ldquo;珍藏&rdquo;是什么体验?最近,情感博主@公主是用鲜花做的,火了!仅仅凭借一条视频,光小红书就有超过128万人,为她疯狂点赞!更疯狂的是,这
  • 华为HarmonyOS 4升级计划公布:首批34款机型今日开启公测

    8月4日消息,今天下午华为正式发布了HarmonyOS 4系统,在更流畅的前提下,还带来了不少新功能,UI设计也有变化,会让手机焕然一新。华为宣布,首批机型将会在
  • “买真退假” 这种“羊毛”不能薅

    □ 法治日报 记者 王春   □ 本报通讯员 胡佳丽  2020年初,还在上大学的小东加入了一个大学生兼职QQ群。群主&ldquo;七王&rdquo;在群里介绍一些刷单赚
Top