前言
说是实现,但其实我们只是在 React Scheduler 源码的基础上进行了简化,省略掉一些繁琐的细节,添加了丰富的注释,保证代码可直接执行。
大家可以复制代码到编辑器中,直接运行,非常适合学习 React 源码用。
如果看注释还不了解,欢迎补充学习这个专栏的文章。
源码 Schedule.js
// 引入最小堆封装代码
import {push, pop, peek} from './ScheduleMinHeap.js';
// 浏览器提供的 API,获取从 time origin(当前文档生命周期的开始节点时间) 之后到当前调用时经过的时间,它以一个恒定的速率慢慢增加的,不会受到系统时间的影响,具体参考:https://juejin.cn/post/7171633315336683528
let getCurrentTime = () => performance.now();
// Scheduler 优先级划分,数字越小优先级越高,0 表示没有优先级
const NoPriority = 0;
const ImmediatePriority = 1;
const UserBlockingPriority = 2;
const NormalPriority = 3;
const LowPriority = 4;
const IdlePriority = 5;
// Scheduler 根据优先级设置的对应 timeout 时间,越小越紧急
// 在 React 中,任务是可以被打断的,但是任务不能一直被打断,所以要设置一个超时时间,过了这个时间就必须立刻执行
// timeout 就表示超时时间
var IMMEDIATE_PRIORITY_TIMEOUT = -1;
var USER_BLOCKING_PRIORITY_TIMEOUT = 250;
var NORMAL_PRIORITY_TIMEOUT = 5000;
var LOW_PRIORITY_TIMEOUT = 10000;
// 为什么是 1073741823,查看:https://juejin.cn/post/7171633315336683528
var IDLE_PRIORITY_TIMEOUT = 1073741823;
// 普通任务队列,它是一个最小堆结构,最小堆查看:https://juejin.cn/post/7168283003037155359
var taskQueue = [];
// 延时任务队列,它同样是一个最小堆结构
var timerQueue = [];
// taskId
var taskIdCounter = 1;
// 任务队列是否正在被遍历执行,workLoop 执行前为 true,执行完成后改为 false
var isPerformingWork = false;
// 是否有正在执行的 requestHostCallback,它会在 requestHostCallback 调用前设为 true,workLoop 执行前改为 false
var isHostCallbackScheduled = false;
// 是否有正在执行的 requestHostTimeout,它会在 requestHostTimeout 执行前设为 true,cancenlHostTimeout 和 handleTimeout 中设为 false
var isHostTimeoutScheduled = false;
// message loop 是否正在执行,它会在 schedulePerformWorkUntilDeadline 前设为 true,在任务队列执行完毕后设为 false
let isMessageLoopRunning = false;
// 记录 requestHostCallback 执行时传入的 callback 函数,也就是 flushWork
let scheduledHostCallback = null;
// 用于 cancelHostTimeout 取消 requestHostTimeout
let taskTimeoutID = -1;
// 记录当前正在执行的任务
var currentTask = null;
var currentPriorityLevel = NormalPriority;
// 这里是调度的开始
function unstable_scheduleCallback(priorityLevel, callback, options) {var currentTime = getCurrentTime();// 任务被安排调度的时间,相当于去银行时的点击排号机器的那个时间var startTime;if (typeof options === 'object' && options !== null) {var delay =