scheduler
内容
getCurrentTime
const getCurrentTime = () => performance.now();
define("getCurrentTime", getCurrentTime);
sleep
const getCurrentTime = require("getCurrentTime");
const sleep = (tm) => {
let startTime = getCurrentTime();
while (getCurrentTime() - startTime <= tm) {
// sleep
}
};
define("sleep", sleep);
TaskQueue
class TaskQueue {
constructor() {
this.queue = [];
}
push(task) {
this.queue.unshift(task);
}
peek() {
return this.queue[this.queue.length - 1];
}
pop() {
return this.queue.pop();
}
}
define("TaskQueue", TaskQueue);
Scheduler
const getCurrentTime = require("getCurrentTime");
const TaskQueue = require("TaskQueue");
const frameInterval = 1000 / 60;
class Scheduler {
constructor() {
this.taskQueue = new TaskQueue();
this.taskIdCounter = 0;
//
this.isHostCallbackScheduled = false;
this.isPerformingWork = false;
this.startTime = -1;
this.scheduledHostCallback = null;
this.isMessageLoopRunning = false;
this.cannel = new MessageChannel();
this.cannel.port1.onmessage = this.performWorkUntilDeadline.bind(this);
}
commitTask(callback) {
let currentTime = getCurrentTime();
const startTime = currentTime;
const timeout = 0; // ms
const newTask = {
id: this.taskIdCounter++,
callback,
startTime,
};
this.taskQueue.push(newTask);
if (!this.isHostCallbackScheduled && !this.isPerformingWork) {
this.isHostCallbackScheduled = true;
this.requestHostCallback(this.flushWork);
}
}
requestHostCallback(cb) {
this.scheduledHostCallback = cb;
if (!this.isMessageLoopRunning) {
this.isMessageLoopRunning = true;
this.schedulePerformWorkUntilDeadline();
}
}
// 发起事件开始执行
schedulePerformWorkUntilDeadline() {
this.cannel.port2.postMessage(null);
}
flushWork() {
this.isHostCallbackScheduled = false;
try {
return this.workLoop();
} finally {
this.currentTask = null;
this.isPerformingWork = false;
}
}
workLoop() {
this.currentTask = this.taskQueue.peek();
while (this.currentTask != null) {
const shouldCallTask = this.shouldYieldToHost();
if (shouldCallTask) {
break;
}
const callback = this.currentTask.callback;
if (typeof callback === "function") {
const continuationCallback = callback();
if (typeof continuationCallback === "function") {
this.currentTask.callback = continuationCallback;
} else {
if (this.currentTask === this.taskQueue.peek()) {
this.taskQueue.pop();
}
}
} else {
this.taskQueue.pop();
}
this.currentTask = this.taskQueue.peek();
}
if (this.currentTask != null) {
return true;
}
return false;
}
performWorkUntilDeadline() {
if (this.scheduledHostCallback !== null) {
const currentTime = getCurrentTime();
this.startTime = currentTime;
let hasMoreWork = true;
try {
hasMoreWork = this.scheduledHostCallback();
} finally {
if (hasMoreWork) {
this.schedulePerformWorkUntilDeadline();
} else {
this.isMessageLoopRunning = false;
this.scheduledHostCallback = null;
}
}
}
}
shouldYieldToHost() {
const timeElapsed = getCurrentTime() - this.startTime;
if (timeElapsed < frameInterval) {
return false;
}
return true;
}
}
define("scheduler", Scheduler);
<script type="module">
const Scheduler = require("scheduler");
const sleep = require("sleep");
const scheduler = new Scheduler();
const runTaskButton = document.getElementById("runTask");
const draw = document.getElementById("draw");
runTaskButton.onclick = () => {
console.log("提交任务");
scheduler.commitTask(() => {
console.log("hello world1");
sleep(200);
draw.innerHTML = "task1";
});
scheduler.commitTask(() => {
console.log("hello world2");
sleep(200);
draw.innerHTML = "task2";
});
scheduler.commitTask(() => {
console.log("hello world3");
sleep(200);
draw.innerHTML = "task3";
});
scheduler.commitTask(() => {
console.log("hello world4");
sleep(200);
draw.innerHTML = "task4";
});
scheduler.commitTask(() => {
console.log("hello world5");
sleep(200);
draw.innerHTML = "task5";
});
};
</script>
<button id="runTask">运行任务</button>
<div id="draw"></div>