【React】调度系统 - Scheduler

Scheduler

先来整体的看一下调度系统是如何工作的:

调度系统的工作机制基本如图中所示:

  1. 我们在数据更新的同时,会注册一个 “渲染任务” 到调度系统中

  2. 调度系统将 “渲染任务” 加入到 “任务队列” 中进行排序(实际上是个最小堆),等待执行

  3. 同时,调度系统会注册 “调度任务” 到 **macrotask**

  4. “调度任务” 执行时,会按顺序执行 “任务队列” 中的任务,直到为空或者本次 “调度任务” 的时间片到时。

  5. 如果时间片到时,而 “任务队列” 依然存在为执行的任务,需要再次注册 “调度任务” 到 **macrotask**

任务“队列”

React 是通过 **scheduleCallback** 接口来向调度系统中来注册任务。其中 **priority** 为本次任务的优先级,**callback** 为等待执行的任务。

这样的数据在调度系统内部会被转化成任务 **Task** 来进行保存。其中值得一说的是,**priority** 优先级在这里会被映射为超时时间 **timeout**,即该任务在多久内必须要被执行。

可以看到图中 Task 记录的是任务的过期时间 **expirationTime** ,其实 **expirationTime = now() + timeout**

最终任务被添加到任务“队列”(其实是个堆结构)中,并按照任务的过期时间 **expirationTime** 进行排序,这样就可以每次从 “队列” 中取出最早要过期的任务先执行。

调度任务的工作

调度任务是指:将任务“队列”中的任务拿出来,依次执行的工作。具体的话,大家可以看 Scheduler 模块中的 **flushWork** 函数。

如上图所示,当有任务被添加到调度系统中时,调度系统不是立刻去执行 “调度任务”,而是将 “调度任务” 添加到 **macrotask** 中,等待执行。

这样一来,就不会因为任务执行太久,而阻塞同步代码的执行了。

其实,这也就变相地帮助 React 实现了 Automatic Batching

调度任务呢其实就是遍历任务“队列”去依次执行,如果所有任务都执行完成,那么调度任务自然可以结束。

除此之外呢,调度任务还有另外一种停止机制:时间切片

时间切片

什么是时间切片呢?其实每次调度任务的执行都有限额的时间(比如 5 毫秒),当执行超过这个时间的时候,调度系统就需要先停下,注册下次的调度任务到 **macrotask**

这意味着,这个时候调度任务交出了JS线程的 “控制权” ,我们可以去处理交互产生的回调、页面渲染等事情了。

我们再引用一下《Concurrent 的奥秘》中的例子,它们的执行情况如下图:

上图这个是没有进行时间切片的同步渲染过程。可以看到,React 的 “渲染” 过程花了 50 毫秒才完成。在此期间,我们无法做任何事情,页面卡在了呢个地方,直到 JS 执行结束。

这个则是使用了时间切片的并发渲染过程,可以看到,对于一些耗时的 “渲染” 过程,React 将它 “拆分” 成了很多个 5 毫秒的小任务。

每个小任务执行完,都会把 “控制权” 交还,这时浏览器可以查看是否有交互回调需要执行,或者可以让浏览器渲染一帧画面。这样就使得我们页面始终保持了响应能力,不会卡住。

对于调度任务来说,它会在每处理完一个任务后,检查本次执行是否超时。如果超时就停下来,注册下一次的任务,如此循环往复… 时间切片就是这样在调度任务中实际应用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值