Use let or const to avoid scope issues and hoisting
/* eslint-disable no-var */
1/**2 * Copyright (c) Meta Platforms, Inc. and affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 *7 * @flow8 */910/* eslint-disable no-var */1112import type {PriorityLevel} from '../SchedulerPriorities';1314import {15 enableProfiling,16 frameYieldMs,17 userBlockingPriorityTimeout,18 lowPriorityTimeout,19 normalPriorityTimeout,20 enableRequestPaint,21 enableAlwaysYieldScheduler,22} from '../SchedulerFeatureFlags';2324import {push, pop, peek} from '../SchedulerMinHeap';2526// TODO: Use symbols?27import {28 ImmediatePriority,29 UserBlockingPriority,30 NormalPriority,31 LowPriority,32 IdlePriority,33} from '../SchedulerPriorities';34import {35 markTaskRun,36 markTaskYield,37 markTaskCompleted,38 markTaskCanceled,39 markTaskErrored,40 markSchedulerSuspended,41 markSchedulerUnsuspended,42 markTaskStart,43 stopLoggingProfilingEvents,44 startLoggingProfilingEvents,45} from '../SchedulerProfiling';4647export type Callback = boolean => ?Callback;4849export opaque type Task = {50 id: number,51 callback: Callback | null,52 priorityLevel: PriorityLevel,53 startTime: number,54 expirationTime: number,55 sortIndex: number,56 isQueued?: boolean,57};5859let getCurrentTime: () => number | DOMHighResTimeStamp;60const hasPerformanceNow =61 // $FlowFixMe[method-unbinding]62 typeof performance === 'object' && typeof performance.now === 'function';6364if (hasPerformanceNow) {65 const localPerformance = performance;66 getCurrentTime = () => localPerformance.now();67} else {68 const localDate = Date;69 const initialTime = localDate.now();70 getCurrentTime = () => localDate.now() - initialTime;71}7273// Max 31 bit integer. The max integer size in V8 for 32-bit systems.74// Math.pow(2, 30) - 175// 0b11111111111111111111111111111176var maxSigned31BitInt = 1073741823;7778// Tasks are stored on a min heap79var taskQueue: Array<Task> = [];80var timerQueue: Array<Task> = [];8182// Incrementing id counter. Used to maintain insertion order.83var taskIdCounter = 1;8485var currentTask = null;86var currentPriorityLevel: PriorityLevel = NormalPriority;8788// This is set while performing work, to prevent re-entrance.89var isPerformingWork = false;9091var isHostCallbackScheduled = false;92var isHostTimeoutScheduled = false;9394var needsPaint = false;9596// Capture local references to native APIs, in case a polyfill overrides them.97const localSetTimeout = typeof setTimeout === 'function' ? setTimeout : null;98const localClearTimeout =99 typeof clearTimeout === 'function' ? clearTimeout : null;100const localSetImmediate =101 typeof setImmediate !== 'undefined' ? setImmediate : null; // IE and Node.js + jsdom102103function advanceTimers(currentTime: number) {104 // Check for tasks that are no longer delayed and add them to the queue.105 let timer = peek(timerQueue);106 while (timer !== null) {107 if (timer.callback === null) {108 // Timer was cancelled.109 pop(timerQueue);110 } else if (timer.startTime <= currentTime) {111 // Timer fired. Transfer to the task queue.112 pop(timerQueue);113 timer.sortIndex = timer.expirationTime;114 push(taskQueue, timer);115 // $FlowFixMe[constant-condition]116 if (enableProfiling) {117 markTaskStart(timer, currentTime);118 timer.isQueued = true;119 }120 } else {121 // Remaining timers are pending.122 return;123 }124 timer = peek(timerQueue);125 }126}127128function handleTimeout(currentTime: number) {129 isHostTimeoutScheduled = false;130 advanceTimers(currentTime);131132 if (!isHostCallbackScheduled) {133 if (peek(taskQueue) !== null) {134 isHostCallbackScheduled = true;135 requestHostCallback();136 } else {137 const firstTimer = peek(timerQueue);138 if (firstTimer !== null) {139 requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime);140 }141 }142 }143}144145function flushWork(initialTime: number) {146 // $FlowFixMe[constant-condition]147 if (enableProfiling) {148 markSchedulerUnsuspended(initialTime);149 }150151 // We'll need a host callback the next time work is scheduled.152 isHostCallbackScheduled = false;153 if (isHostTimeoutScheduled) {154 // We scheduled a timeout but it's no longer needed. Cancel it.155 isHostTimeoutScheduled = false;156 cancelHostTimeout();157 }158159 isPerformingWork = true;160 const previousPriorityLevel = currentPriorityLevel;161 try {162 // $FlowFixMe[constant-condition]163 if (enableProfiling) {164 try {165 return workLoop(initialTime);166 } catch (error) {167 if (currentTask !== null) {168 const currentTime = getCurrentTime();169 // $FlowFixMe[incompatible-call] found when upgrading Flow170 // $FlowFixMe[incompatible-type]171 markTaskErrored(currentTask, currentTime);172 // $FlowFixMe[incompatible-use] found when upgrading Flow173 currentTask.isQueued = false;174 }175 throw error;176 }177 } else {178 // No catch in prod code path.179 return workLoop(initialTime);180 }181 } finally {182 currentTask = null;183 currentPriorityLevel = previousPriorityLevel;184 isPerformingWork = false;185 // $FlowFixMe[constant-condition]186 if (enableProfiling) {187 const currentTime = getCurrentTime();188 markSchedulerSuspended(currentTime);189 }190 }191}192193function workLoop(initialTime: number) {194 let currentTime = initialTime;195 advanceTimers(currentTime);196 currentTask = peek(taskQueue);197 while (currentTask !== null) {198 if (!enableAlwaysYieldScheduler) {199 if (currentTask.expirationTime > currentTime && shouldYieldToHost()) {200 // This currentTask hasn't expired, and we've reached the deadline.201 break;202 }203 }204 // $FlowFixMe[incompatible-use] found when upgrading Flow205 const callback = currentTask.callback;206 if (typeof callback === 'function') {207 // $FlowFixMe[incompatible-use] found when upgrading Flow208 currentTask.callback = null;209 // $FlowFixMe[incompatible-use] found when upgrading Flow210 currentPriorityLevel = currentTask.priorityLevel;211 // $FlowFixMe[incompatible-use] found when upgrading Flow212 const didUserCallbackTimeout = currentTask.expirationTime <= currentTime;213 // $FlowFixMe[constant-condition]214 if (enableProfiling) {215 // $FlowFixMe[incompatible-type] found when upgrading Flow216 markTaskRun(currentTask, currentTime);217 }218 const continuationCallback = callback(didUserCallbackTimeout);219 currentTime = getCurrentTime();220 if (typeof continuationCallback === 'function') {221 // If a continuation is returned, immediately yield to the main thread222 // regardless of how much time is left in the current time slice.223 // $FlowFixMe[incompatible-use] found when upgrading Flow224 currentTask.callback = continuationCallback;225 // $FlowFixMe[constant-condition]226 if (enableProfiling) {227 // $FlowFixMe[incompatible-type] found when upgrading Flow228 markTaskYield(currentTask, currentTime);229 }230 advanceTimers(currentTime);231 return true;232 } else {233 // $FlowFixMe[constant-condition]234 if (enableProfiling) {235 // $FlowFixMe[incompatible-type] found when upgrading Flow236 markTaskCompleted(currentTask, currentTime);237 // $FlowFixMe[incompatible-use] found when upgrading Flow238 currentTask.isQueued = false;239 }240 if (currentTask === peek(taskQueue)) {241 pop(taskQueue);242 }243 advanceTimers(currentTime);244 }245 } else {246 pop(taskQueue);247 }248 currentTask = peek(taskQueue);249 if (enableAlwaysYieldScheduler) {250 if (currentTask === null || currentTask.expirationTime > currentTime) {251 // This currentTask hasn't expired we yield to the browser task.252 break;253 }254 }255 }256 // Return whether there's additional work257 if (currentTask !== null) {258 return true;259 } else {260 const firstTimer = peek(timerQueue);261 if (firstTimer !== null) {262 requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime);263 }264 return false;265 }266}267268function unstable_runWithPriority<T>(269 priorityLevel: PriorityLevel,270 eventHandler: () => T,271): T {272 switch (priorityLevel) {273 case ImmediatePriority:274 case UserBlockingPriority:275 case NormalPriority:276 case LowPriority:277 case IdlePriority:278 break;279 default:280 priorityLevel = NormalPriority;281 }282283 var previousPriorityLevel = currentPriorityLevel;284 currentPriorityLevel = priorityLevel;285286 try {287 return eventHandler();288 } finally {289 currentPriorityLevel = previousPriorityLevel;290 }291}292293function unstable_next<T>(eventHandler: () => T): T {294 var priorityLevel: PriorityLevel;295 switch (currentPriorityLevel) {296 case ImmediatePriority:297 case UserBlockingPriority:298 case NormalPriority:299 // Shift down to normal priority300 priorityLevel = NormalPriority;301 break;302 default:303 // Anything lower than normal priority should remain at the current level.304 priorityLevel = currentPriorityLevel;305 break;306 }307308 var previousPriorityLevel = currentPriorityLevel;309 currentPriorityLevel = priorityLevel;310311 try {312 return eventHandler();313 } finally {314 currentPriorityLevel = previousPriorityLevel;315 }316}317318function unstable_wrapCallback<T: (...Array<mixed>) => mixed>(callback: T): T {319 var parentPriorityLevel = currentPriorityLevel;320 // $FlowFixMe[incompatible-type]321 // $FlowFixMe[missing-this-annot]322 return function () {323 // This is a fork of runWithPriority, inlined for performance.324 var previousPriorityLevel = currentPriorityLevel;325 currentPriorityLevel = parentPriorityLevel;326327 try {328 return callback.apply(this, arguments);329 } finally {330 currentPriorityLevel = previousPriorityLevel;331 }332 };333}334335function unstable_scheduleCallback(336 priorityLevel: PriorityLevel,337 callback: Callback,338 options?: {delay: number},339): Task {340 var currentTime = getCurrentTime();341342 var startTime;343 // $FlowFixMe[invalid-compare]344 if (typeof options === 'object' && options !== null) {345 var delay = options.delay;346 if (typeof delay === 'number' && delay > 0) {347 startTime = currentTime + delay;348 } else {349 startTime = currentTime;350 }351 } else {352 startTime = currentTime;353 }354355 var timeout;356 switch (priorityLevel) {357 case ImmediatePriority:358 // Times out immediately359 timeout = -1;360 break;361 case UserBlockingPriority:362 // Eventually times out363 timeout = userBlockingPriorityTimeout;364 break;365 case IdlePriority:366 // Never times out367 timeout = maxSigned31BitInt;368 break;369 case LowPriority:370 // Eventually times out371 timeout = lowPriorityTimeout;372 break;373 case NormalPriority:374 default:375 // Eventually times out376 timeout = normalPriorityTimeout;377 break;378 }379380 var expirationTime = startTime + timeout;381382 var newTask: Task = {383 id: taskIdCounter++,384 callback,385 priorityLevel,386 startTime,387 expirationTime,388 sortIndex: -1,389 };390 // $FlowFixMe[constant-condition]391 if (enableProfiling) {392 newTask.isQueued = false;393 }394395 if (startTime > currentTime) {396 // This is a delayed task.397 newTask.sortIndex = startTime;398 push(timerQueue, newTask);399 if (peek(taskQueue) === null && newTask === peek(timerQueue)) {400 // All tasks are delayed, and this is the task with the earliest delay.401 if (isHostTimeoutScheduled) {402 // Cancel an existing timeout.403 cancelHostTimeout();404 } else {405 isHostTimeoutScheduled = true;406 }407 // Schedule a timeout.408 requestHostTimeout(handleTimeout, startTime - currentTime);409 }410 } else {411 newTask.sortIndex = expirationTime;412 push(taskQueue, newTask);413 // $FlowFixMe[constant-condition]414 if (enableProfiling) {415 markTaskStart(newTask, currentTime);416 newTask.isQueued = true;417 }418 // Schedule a host callback, if needed. If we're already performing work,419 // wait until the next time we yield.420 if (!isHostCallbackScheduled && !isPerformingWork) {421 isHostCallbackScheduled = true;422 requestHostCallback();423 }424 }425426 return newTask;427}428429function unstable_cancelCallback(task: Task) {430 // $FlowFixMe[constant-condition]431 if (enableProfiling) {432 if (task.isQueued) {433 const currentTime = getCurrentTime();434 markTaskCanceled(task, currentTime);435 task.isQueued = false;436 }437 }438439 // Null out the callback to indicate the task has been canceled. (Can't440 // remove from the queue because you can't remove arbitrary nodes from an441 // array based heap, only the first one.)442 task.callback = null;443}444445function unstable_getCurrentPriorityLevel(): PriorityLevel {446 return currentPriorityLevel;447}448449let isMessageLoopRunning = false;450let taskTimeoutID: TimeoutID = -1 as any;451452// Scheduler periodically yields in case there is other work on the main453// thread, like user events. By default, it yields multiple times per frame.454// It does not attempt to align with frame boundaries, since most tasks don't455// need to be frame aligned; for those that do, use requestAnimationFrame.456let frameInterval: number = frameYieldMs;457let startTime = -1;458459function shouldYieldToHost(): boolean {460 if (!enableAlwaysYieldScheduler && enableRequestPaint && needsPaint) {461 // Yield now.462 return true;463 }464 const timeElapsed = getCurrentTime() - startTime;465 if (timeElapsed < frameInterval) {466 // The main thread has only been blocked for a really short amount of time;467 // smaller than a single frame. Don't yield yet.468 return false;469 }470 // Yield now.471 return true;472}473474function requestPaint() {475 // $FlowFixMe[constant-condition]476 if (enableRequestPaint) {477 needsPaint = true;478 }479}480481function forceFrameRate(fps: number) {482 if (fps < 0 || fps > 125) {483 // Using console['error'] to evade Babel and ESLint484 console['error'](485 'forceFrameRate takes a positive int between 0 and 125, ' +486 'forcing frame rates higher than 125 fps is not supported',487 );488 return;489 }490 if (fps > 0) {491 frameInterval = Math.floor(1000 / fps);492 } else {493 // reset the framerate494 frameInterval = frameYieldMs;495 }496}497498const performWorkUntilDeadline = () => {499 // $FlowFixMe[constant-condition]500 if (enableRequestPaint) {501 needsPaint = false;502 }503 if (isMessageLoopRunning) {504 const currentTime = getCurrentTime();505 // Keep track of the start time so we can measure how long the main thread506 // has been blocked.507 startTime = currentTime;508509 // If a scheduler task throws, exit the current browser task so the510 // error can be observed.511 //512 // Intentionally not using a try-catch, since that makes some debugging513 // techniques harder. Instead, if `flushWork` errors, then `hasMoreWork` will514 // remain true, and we'll continue the work loop.515 let hasMoreWork = true;516 try {517 hasMoreWork = flushWork(currentTime);518 } finally {519 if (hasMoreWork) {520 // If there's more work, schedule the next message event at the end521 // of the preceding one.522 schedulePerformWorkUntilDeadline();523 } else {524 isMessageLoopRunning = false;525 }526 }527 }528};529530let schedulePerformWorkUntilDeadline;531if (typeof localSetImmediate === 'function') {532 // Node.js and old IE.533 // There's a few reasons for why we prefer setImmediate.534 //535 // Unlike MessageChannel, it doesn't prevent a Node.js process from exiting.536 // (Even though this is a DOM fork of the Scheduler, you could get here537 // with a mix of Node.js 15+, which has a MessageChannel, and jsdom.)538 // https://github.com/facebook/react/issues/20756539 //540 // But also, it runs earlier which is the semantic we want.541 // If other browsers ever implement it, it's better to use it.542 // Although both of these would be inferior to native scheduling.543 schedulePerformWorkUntilDeadline = () => {544 localSetImmediate(performWorkUntilDeadline);545 };546} else if (typeof MessageChannel !== 'undefined') {547 // DOM and Worker environments.548 // We prefer MessageChannel because of the 4ms setTimeout clamping.549 const channel = new MessageChannel();550 const port = channel.port2;551 channel.port1.onmessage = performWorkUntilDeadline;552 schedulePerformWorkUntilDeadline = () => {553 port.postMessage(null);554 };555} else {556 // We should only fallback here in non-browser environments.557 schedulePerformWorkUntilDeadline = () => {558 // $FlowFixMe[not-a-function] nullable value559 localSetTimeout(performWorkUntilDeadline, 0);560 };561}562563function requestHostCallback() {564 if (!isMessageLoopRunning) {565 isMessageLoopRunning = true;566 schedulePerformWorkUntilDeadline();567 }568}569570function requestHostTimeout(571 callback: (currentTime: number) => void,572 ms: number,573) {574 // $FlowFixMe[not-a-function] nullable value575 taskTimeoutID = localSetTimeout(() => {576 callback(getCurrentTime());577 }, ms);578}579580function cancelHostTimeout() {581 // $FlowFixMe[not-a-function] nullable value582 localClearTimeout(taskTimeoutID);583 taskTimeoutID = -1 as any as TimeoutID;584}585586export {587 ImmediatePriority as unstable_ImmediatePriority,588 UserBlockingPriority as unstable_UserBlockingPriority,589 NormalPriority as unstable_NormalPriority,590 IdlePriority as unstable_IdlePriority,591 LowPriority as unstable_LowPriority,592 unstable_runWithPriority,593 unstable_next,594 unstable_scheduleCallback,595 unstable_cancelCallback,596 unstable_wrapCallback,597 unstable_getCurrentPriorityLevel,598 shouldYieldToHost as unstable_shouldYield,599 requestPaint as unstable_requestPaint,600 getCurrentTime as unstable_now,601 forceFrameRate as unstable_forceFrameRate,602};603604export const unstable_Profiling: {605 startLoggingProfilingEvents(): void,606 stopLoggingProfilingEvents(): ArrayBuffer | null,607 // $FlowFixMe[constant-condition]608} | null = enableProfiling609 ? {610 startLoggingProfilingEvents,611 stopLoggingProfilingEvents,612 }613 : null;
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.