自己的名词理解
为了达成某一个
目的,协调多个任务的算法。这个目的比如拿浏览器来说,让用户感觉页面流畅。
React Schedule包的调度
Schedule
打断分两层含义
来个Demo
高优先级打断低优先级(多个任务)
优先级队列的内容,此处省略
还是说说主要流程吧
-
unstable_scheduleCallback调度当前最高优先级的工作 unstable_scheduleCallback -
重新执行workLoop拿到优先级高的任务
时间切片用完了(单个任务yieldInterval)
针对非同步优先级
当前work由于时间切片用尽,被打断(break)。没有其他更高优先级的work与它竞争,下一次还是当前work
yieldInterval分为yield(可以理解暂停)interval(间隔)
中断(时间切片用完了)
let currentTime = initialTime;
advanceTimers(currentTime);
currentTask = peek(taskQueue);
while (
currentTask !== null &&
!(enableSchedulerDebugging && isSchedulerPaused)
) {
if (
currentTask.expirationTime > currentTime &&
(!hasTimeRemaining || shouldYieldToHost())
) {
//这里处理时间切片用完了的情况`当前work`由于时间切片用尽,被打断。没有其他更高优的work与他竞争,下一次perform还是当前work
// This currentTask hasn't expired, and we've reached the deadline.
break;
}
...
}
我们关注
break的条件。
currentTask.expirationTime > currentTime && (!hasTimeRemaining || shouldYieldToHost())
翻译一下: 任务没过期,并且时间切片用完了
shouldYieldToHost = function() {
const currentTime = getCurrentTime();
if (currentTime >= deadline) {
// There's no time left. We may want to yield control of the main
// thread, so the browser can perform high priority tasks. The main ones
// are painting and user input. If there's a pending paint or a pending
// input, then we should yield. But if there's neither, then we can
// yield less often while remaining responsive. We'll eventually yield
// regardless, since there could be a pending paint that wasn't
// accompanied by a call to `requestPaint`, or other main thread tasks
// like network events.
if (needsPaint || scheduling.isInputPending()) {
// There is either a pending paint or a pending input.
return true;
}
// There's no pending input. Only yield if we've reached the max
// yield interval.
return currentTime >= maxYieldInterval;
} else {
// There's still time left in the frame.
return false;
}
};
...
打开有道🤪
没时间了。我们可能希望放弃对主线程的控制,这样浏览器就可以执行高优先级的任务。主要的是绘制和用户输入。如果有一个挂起的油漆(paint)或一个挂起的输入,那么我们应该让步。
expirationTime计算公式: var expirationTime = startTime + timeout;
startTime: 当前时间
timeout: 优先级对应的数字
// Times out immediately
var IMMEDIATE_PRIORITY_TIMEOUT = -1;
// Eventually times out
var USER_BLOCKING_PRIORITY_TIMEOUT = 250;
var NORMAL_PRIORITY_TIMEOUT = 5000;
var LOW_PRIORITY_TIMEOUT = 10000;
// Never times out
var IDLE_PRIORITY_TIMEOUT = maxSigned31BitInt;
// Tasks are stored on a min heap
var taskQueue = [];
var timerQueue = [];
由此可以得出,当任务是同步的优先级的时候
currentTask.expirationTime永远小于currentTime所以永远不会break(也就是任务过期了,我要立马处理),react在commit阶段是同步的,因为采用的是同步优先级。
实践
同步优先级下,界面是一下子出来。而其他优先级是过度的出来。原因是时间切片用完了,把控制权交给浏览器,浏览器去
paint
总结
时间切片是一种思想,核心是交出浏览器控制权(React将控制权交还给浏览器)。可以用许多方式实现如
setTimeoutyield等,React Schedule用了messageChannel。关键是yieldInterval,比较鸡贼