var IMMEDIATE_PRIORITY_TIMEOUT = -1;
var USER_BLOCKING_PRIORITY_TIMEOUT = 250; var NORMAL_PRIORITY_TIMEOUT = 5000; var LOW_PRIORITY_TIMEOUT = 10000;
var IDLE_PRIORITY_TIMEOUT = maxSigned31BitInt;
var taskQueue = [];
var timerQueue = [];
function unstable_scheduleCallback(priorityLevel, callback, options) { var currentTime = getCurrentTime(); var startTime; if (typeof options === "object" && options !== null) { var delay = options.delay; if (typeof delay === "number" && delay > 0) { startTime = currentTime + delay; } else { startTime = currentTime; } } else { startTime = currentTime; }
var timeout; switch (priorityLevel) { case ImmediatePriority: timeout = IMMEDIATE_PRIORITY_TIMEOUT; break; case UserBlockingPriority: timeout = USER_BLOCKING_PRIORITY_TIMEOUT; break; case IdlePriority: timeout = IDLE_PRIORITY_TIMEOUT; break; case LowPriority: timeout = LOW_PRIORITY_TIMEOUT; break; case NormalPriority: default: timeout = NORMAL_PRIORITY_TIMEOUT; break; } var expirationTime = startTime + timeout; var newTask = { id: taskIdCounter++, callback, priorityLevel, startTime, expirationTime, sortIndex: -1, }; if (enableProfiling) { newTask.isQueued = false; } if (startTime > currentTime) { newTask.sortIndex = startTime; push(timerQueue, newTask); if (peek(taskQueue) === null && newTask === peek(timerQueue)) { if (isHostTimeoutScheduled) { cancelHostTimeout(); } else { isHostTimeoutScheduled = true; } requestHostTimeout(handleTimeout, startTime - currentTime); } } else { newTask.sortIndex = expirationTime; push(taskQueue, newTask); if (enableProfiling) { markTaskStart(newTask, currentTime); newTask.isQueued = true; } if (!isHostCallbackScheduled && !isPerformingWork) { isHostCallbackScheduled = true; requestHostCallback(flushWork); } }
return newTask; }
function requestHostCallback(callback) { scheduledHostCallback = callback; if (!isMessageLoopRunning) { isMessageLoopRunning = true; schedulePerformWorkUntilDeadline(); } }
let schedulePerformWorkUntilDeadline; if (typeof localSetImmediate === "function") { schedulePerformWorkUntilDeadline = () => { localSetImmediate(performWorkUntilDeadline); }; } else if (typeof MessageChannel !== "undefined") { const channel = new MessageChannel(); const port = channel.port2; channel.port1.onmessage = performWorkUntilDeadline; schedulePerformWorkUntilDeadline = () => { port.postMessage(null); }; } else { schedulePerformWorkUntilDeadline = () => { localSetTimeout(performWorkUntilDeadline, 0); }; }
let startTime = -1;
const performWorkUntilDeadline = () => { if (scheduledHostCallback !== null) { const currentTime = getCurrentTime(); startTime = currentTime; const hasTimeRemaining = true; let hasMoreWork = true; try { hasMoreWork = scheduledHostCallback(hasTimeRemaining, currentTime); } finally { if (hasMoreWork) { schedulePerformWorkUntilDeadline(); } else { isMessageLoopRunning = false; scheduledHostCallback = null; } } } else { isMessageLoopRunning = false; } needsPaint = false; };
function flushWork(hasTimeRemaining, initialTime) { if (enableProfiling) { markSchedulerUnsuspended(initialTime); }
isHostCallbackScheduled = false; if (isHostTimeoutScheduled) { isHostTimeoutScheduled = false; cancelHostTimeout(); }
isPerformingWork = true; const previousPriorityLevel = currentPriorityLevel; try { if (enableProfiling) { try { return workLoop(hasTimeRemaining, initialTime); } catch (error) { if (currentTask !== null) { const currentTime = getCurrentTime(); markTaskErrored(currentTask, currentTime); currentTask.isQueued = false; } throw error; } } else { return workLoop(hasTimeRemaining, initialTime); } } finally { currentTask = null; currentPriorityLevel = previousPriorityLevel; isPerformingWork = false; if (enableProfiling) { const currentTime = getCurrentTime(); markSchedulerSuspended(currentTime); } } }
function workLoop(hasTimeRemaining, initialTime) { let currentTime = initialTime; advanceTimers(currentTime); currentTask = peek(taskQueue); while (currentTask !== null && !(enableSchedulerDebugging && isSchedulerPaused)) { if (currentTask.expirationTime > currentTime && (!hasTimeRemaining || shouldYieldToHost())) { 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); } if (currentTask !== null) { return true; } else { const firstTimer = peek(timerQueue); if (firstTimer !== null) { requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime); } return false; } }
function advanceTimers(currentTime) { let timer = peek(timerQueue); while (timer !== null) { if (timer.callback === null) { pop(timerQueue); } else if (timer.startTime <= currentTime) { pop(timerQueue); timer.sortIndex = timer.expirationTime; push(taskQueue, timer); if (enableProfiling) { markTaskStart(timer, currentTime); timer.isQueued = true; } } else { return; } timer = peek(timerQueue); } }
let frameInterval = 5;
function shouldYieldToHost() { const timeElapsed = getCurrentTime() - startTime; if (timeElapsed < frameInterval) { return false; }
if (enableIsInputPending) { if (needsPaint) { return true; } if (timeElapsed < continuousInputInterval) { if (isInputPending !== null) { return isInputPending(); } } else if (timeElapsed < maxInterval) { if (isInputPending !== null) { return isInputPending(continuousOptions); } } else { return true; } }
return true; }
|