workloop
schedulerのほう。while文でtaskを消化していって、task === null | shouldYieldToHost()でbreak。
後半は、taskが残っていた場合の再開予約。
以下詳細。
code:js
let currentTime = performance.now();
while (currentTask) {
// まだtaskを先送りできて、そろそろ中断したい。
if (
currentTask.expirationTime > currentTime &&
(!hasTimeRemaining || shouldYieldToHost())
) {
break;
}
// コールバックはたとえば performConcurrentWorkOnRoot.bind(null, root)
const callback = currentTask.callback;
const continuationCallback = callback(false);
// このタスク終了/継続?
if (continuationCallback === null) {
// 終了:タスクをヒープから削除
if (currentTask === peek(taskQueue)) {
pop(taskQueue);
}
} else {
// 継続:callbackを更新
currentTask.callback = continuationCallback;
}
currentTask = peek(taskQueue); // popされるのは終了時のみ → 継続の場合、currentTaskの更新はない。
}
if (currentTask !== null) {
return true;
} else {
//timerQueueを見て、再起動タイミングを予約
const firstTimer = peek(timerQueue);
if (firstTimer !== null) {
requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime);
}
return false;
}
実際のコード。callbackがnullなどfunction以外も渡ってくる想定があるようだが?
code:js
function workLoop(hasTimeRemaining, initialTime) {
let currentTime = initialTime;
advanceTimers(currentTime);
currentTask = peek(taskQueue);
while (
currentTask !== null &&
!(enableSchedulerDebugging && isSchedulerPaused)
) {
if (
currentTask.expirationTime > currentTime &&
(!hasTimeRemaining || shouldYieldToHost())
) {
// This currentTask hasn't expired, and we've reached the deadline.
break;
}
const callback = currentTask.callback;
if (typeof callback === 'function') {
currentTask.callback = null;
currentPriorityLevel = currentTask.priorityLevel;
const didUserCallbackTimeout = currentTask.expirationTime <= currentTime;
if (enableProfiling) {
markTaskRun(currentTask, currentTime);
}
const continuationCallback = callback(didUserCallbackTimeout);
currentTime = getCurrentTime();
if (typeof continuationCallback === 'function') {
currentTask.callback = continuationCallback;
if (enableProfiling) {
markTaskYield(currentTask, currentTime);
}
} else {
if (enableProfiling) {
markTaskCompleted(currentTask, currentTime);
currentTask.isQueued = false;
}
if (currentTask === peek(taskQueue)) {
pop(taskQueue);
}
}
advanceTimers(currentTime);
} else {
pop(taskQueue);
}
currentTask = peek(taskQueue);
}
// Return whether there's additional work
if (currentTask !== null) {
return true;
} else {
const firstTimer = peek(timerQueue);
if (firstTimer !== null) {
requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime);
}
return false;
}
}