Scheduler(调度器)是React的重要组成部分。同时,它也是一个独立的包。任何“连续且可中断”的进程都可以被调度器调度,例如:constwork={count:100};functiondoWork(work){work.count--;console.log('dowork!')}work满足两个条件:工作是连续的。一共需要执行100次,每次执行doWork的调用都是可以中断的。中断恢复后,中断前的work.count可以继续执行。满足这两个条件的工作可以用Scheduler_Front-end训练来调度。调度完成后,Scheduler会在内部生成相应的任务,并在正确的时间执行task.callback:consttask1={//过期时间等于当前时间+优先级对应时间expirationTime:currentTime+priority,callback:doWork。bind(null,work)}本文将讲解Scheduler的实现原理。我知道你不喜欢阅读大段代码,所以本文没有一行代码。文末有Scheduler的源码地址。如果您有兴趣,可以查看一下。工作流程概述Scheduler的工作原理如下图所示,接下来会详细解释:Scheduler中有两个容易混淆的概念:1.delaydelay意思是“任务需要延迟执行的时间”。配置了delay的任务会先进入timerQueue。当延迟对应的时间到期时,任务会被转移到taskQueue中。2.expirationTimeexpirationTime表示“任务过期时间”。并不是所有的任务都会配置延时,没有延时的任务会直接进入taskQueue。这就导致了taskQueue中有多个任务的可能性。如何决定先执行哪个task.callback?Scheduler以task.expirationTime作为排序依据,值越小,priority_web前端训练越高。如果task.expirationTime小于当前时间,不仅优先级最高,而且task.callback的执行也不会被打断。总结一下task的几种情况:配置了延时且延时未过期:任务一定没有执行配置的延时和过期,或者没有配置延时的任务,task.expirationTime还未过期:按照task排序后.expirationTime,按顺序执行task.expirationTimeexpired:优先级最高,同步,不可中断的工作流程详解将流程概览图替换成Scheduler中的具体方法后,完整的工作流程如下:1.执行Scheduler.scheduleCallback根据“是否传递延迟参数”来生成任务,生成的任务会进入timerQueue或taskQueue。2.当timerQueue中第一个任务的延迟时间到期时,执行advanceTimers将timerQueue中的“过期任务”移动到taskQueue中。timerQueue和taskQueue的数据结构都是小顶堆实现的优先级队列。3、接下来执行requestHostCallback方法,会执行新宏任务中的workLoop方法。“在宏任务中执行回调”的方法有很多。Scheduler在浏览器环境中默认使用MessageChannel。如果不支持MessageChannel,则会降级为setTimeout。Node或旧版本的IE将使用setImmediate。1、workLoop方法会循环消费taskQueue中的任务(即执行task.callback),直到满足以下条件之一,中断循环:taskQueue中没有任务且时间片筋疲力尽。2.循环中断后,如果taskQueue不为空,则转第3步。如果timerQueue不为空,转第2步。综上所述,Scheduler完整的执行过程包括两个循环:taskQueue的产生(从timerQueue或scheduleCallback生成的执行)转移到消费的过程(即图中灰色部分),这是一个异步循环taskQueue的具体消费过程(即workLoop方法的执行).这是一个同步循环。想了解“如何在React中使用Scheduler”,可以参考100行代码实现React的核心调度功能
