不用一行代碼,搞懂React調(diào)度器原理
作者:卡頌
來(lái)源:SegmentFault 思否社區(qū)
大家好,我卡頌。
Scheduler(調(diào)度器)是React重要的組成部分。
Scheduler(調(diào)度器)地址:https://github.com/facebook/react/blob/main/packages/scheduler/src/forks/Scheduler.js
同時(shí),他也是個(gè)獨(dú)立的包,任何連續(xù)、可中斷的流程都可以用Scheduler來(lái)調(diào)度,比如:
const work = {count: 100};
function doWork(work) {
work.count--;
console.log('do work!')
}
work滿足兩個(gè)條件:
工作是連續(xù)的。一共需要執(zhí)行100次,每次執(zhí)行時(shí)調(diào)用doWork
工作是可中斷的。中斷恢復(fù)后,接著中斷前的work.count繼續(xù)執(zhí)行就行
滿足這兩個(gè)條件的工作都可以用Scheduler來(lái)調(diào)度。
調(diào)度后,Scheduler內(nèi)部會(huì)生成對(duì)應(yīng)task,并在正確的時(shí)機(jī)執(zhí)行
task.callback:
const task1 = {
// 過(guò)期時(shí)間 等于 當(dāng)前時(shí)間 + 優(yōu)先級(jí)對(duì)應(yīng)時(shí)間
expirationTime: currentTime + priority,
callback: doWork.bind(null, work)
}
本文會(huì)講解Scheduler的實(shí)現(xiàn)原理。知道你不喜歡看大段的代碼,所以本文沒(méi)有一行代碼。文末有Scheduler的源碼地址,感興趣的話可以去看看。
開(kāi)整~
前工作流程概覽
Scheduler的工作原理如下圖,接下來(lái)會(huì)詳細(xì)解釋:

在Scheduler中有兩個(gè)容易混淆的概念:
delay
delay代表task需要延遲執(zhí)行的時(shí)間。配置了delay的task會(huì)先進(jìn)入timerQueue中。
當(dāng)delay對(duì)應(yīng)時(shí)間到期后,該task會(huì)轉(zhuǎn)移到taskQueue中。
expirationTime
expirationTime代表task的過(guò)期時(shí)間。
不是所有task都會(huì)配置delay,沒(méi)有配置delay的task會(huì)直接進(jìn)入taskQueue。這就導(dǎo)致taskQueue中可能存在多個(gè)task。
如何決定哪個(gè)task.callback先執(zhí)行呢?Scheduler根據(jù)task.expirationTime作為排序依據(jù),值越小優(yōu)先級(jí)越高。
如果task.expirationTime小于當(dāng)前時(shí)間,不僅優(yōu)先級(jí)最高,而且task.callback的執(zhí)行不會(huì)被中斷。
總結(jié)一下task的幾種情況:
配置delay且delay未到期:task一定不會(huì)執(zhí)行 配置delay且到期,或者未配置delay的task,同時(shí)task.expirationTime未到期:根據(jù)task.expirationTime排序后,按順序執(zhí)行 task.expirationTime到期的task:優(yōu)先級(jí)最高,且同步、不可中斷
工作流程詳解

執(zhí)行Scheduler.scheduleCallback生成task
當(dāng)timerQueue中第一個(gè)task延遲的時(shí)間到期后,執(zhí)行advanceTimers將到期的task從timerQueue中移到taskQueue中
接下來(lái),執(zhí)行requestHostCallback方法,他會(huì)在新的宏任務(wù)中執(zhí)行workLoop方法
workLoop方法會(huì)循環(huán)消費(fèi)taskQueue中的task(即執(zhí)行task.callback),直到滿足如下條件之一,中斷循環(huán):
taskQueue中不存在task
時(shí)間切片用盡
循環(huán)中斷后,如果taskQueue不為空,則進(jìn)入步驟3。如果timerQueue不為空,則進(jìn)入步驟2
總結(jié)
taskQueue的生產(chǎn)(從timerQueue中移入或執(zhí)行scheduleCallback生成)到消費(fèi)的過(guò)程(即圖中灰色部分),這是個(gè)異步循環(huán)。
taskQueue的具體消費(fèi)過(guò)程(即workLoop方法的執(zhí)行),這是個(gè)同步循環(huán)。

