scheduler-unstable_mock.development.js (17457B)
1/** 2 * @license React 3 * scheduler-unstable_mock.development.js 4 * 5 * Copyright (c) Facebook, Inc. and its affiliates. 6 * 7 * This source code is licensed under the MIT license found in the 8 * LICENSE file in the root directory of this source tree. 9 */ 10 11'use strict'; 12 13if (process.env.NODE_ENV !== "production") { 14 (function() { 15'use strict'; 16 17var enableSchedulerDebugging = false; 18var enableProfiling = false; 19 20function push(heap, node) { 21 var index = heap.length; 22 heap.push(node); 23 siftUp(heap, node, index); 24} 25function peek(heap) { 26 return heap.length === 0 ? null : heap[0]; 27} 28function pop(heap) { 29 if (heap.length === 0) { 30 return null; 31 } 32 33 var first = heap[0]; 34 var last = heap.pop(); 35 36 if (last !== first) { 37 heap[0] = last; 38 siftDown(heap, last, 0); 39 } 40 41 return first; 42} 43 44function siftUp(heap, node, i) { 45 var index = i; 46 47 while (index > 0) { 48 var parentIndex = index - 1 >>> 1; 49 var parent = heap[parentIndex]; 50 51 if (compare(parent, node) > 0) { 52 // The parent is larger. Swap positions. 53 heap[parentIndex] = node; 54 heap[index] = parent; 55 index = parentIndex; 56 } else { 57 // The parent is smaller. Exit. 58 return; 59 } 60 } 61} 62 63function siftDown(heap, node, i) { 64 var index = i; 65 var length = heap.length; 66 var halfLength = length >>> 1; 67 68 while (index < halfLength) { 69 var leftIndex = (index + 1) * 2 - 1; 70 var left = heap[leftIndex]; 71 var rightIndex = leftIndex + 1; 72 var right = heap[rightIndex]; // If the left or right node is smaller, swap with the smaller of those. 73 74 if (compare(left, node) < 0) { 75 if (rightIndex < length && compare(right, left) < 0) { 76 heap[index] = right; 77 heap[rightIndex] = node; 78 index = rightIndex; 79 } else { 80 heap[index] = left; 81 heap[leftIndex] = node; 82 index = leftIndex; 83 } 84 } else if (rightIndex < length && compare(right, node) < 0) { 85 heap[index] = right; 86 heap[rightIndex] = node; 87 index = rightIndex; 88 } else { 89 // Neither child is smaller. Exit. 90 return; 91 } 92 } 93} 94 95function compare(a, b) { 96 // Compare sort index first, then task id. 97 var diff = a.sortIndex - b.sortIndex; 98 return diff !== 0 ? diff : a.id - b.id; 99} 100 101// TODO: Use symbols? 102var ImmediatePriority = 1; 103var UserBlockingPriority = 2; 104var NormalPriority = 3; 105var LowPriority = 4; 106var IdlePriority = 5; 107 108function markTaskErrored(task, ms) { 109} 110 111/* eslint-disable no-var */ 112// Math.pow(2, 30) - 1 113// 0b111111111111111111111111111111 114 115var maxSigned31BitInt = 1073741823; // Times out immediately 116 117var IMMEDIATE_PRIORITY_TIMEOUT = -1; // Eventually times out 118 119var USER_BLOCKING_PRIORITY_TIMEOUT = 250; 120var NORMAL_PRIORITY_TIMEOUT = 5000; 121var LOW_PRIORITY_TIMEOUT = 10000; // Never times out 122 123var IDLE_PRIORITY_TIMEOUT = maxSigned31BitInt; // Tasks are stored on a min heap 124 125var taskQueue = []; 126var timerQueue = []; // Incrementing id counter. Used to maintain insertion order. 127 128var taskIdCounter = 1; // Pausing the scheduler is useful for debugging. 129var currentTask = null; 130var currentPriorityLevel = NormalPriority; // This is set while performing work, to prevent re-entrance. 131 132var isPerformingWork = false; 133var isHostCallbackScheduled = false; 134var isHostTimeoutScheduled = false; 135var currentMockTime = 0; 136var scheduledCallback = null; 137var scheduledTimeout = null; 138var timeoutTime = -1; 139var yieldedValues = null; 140var expectedNumberOfYields = -1; 141var didStop = false; 142var isFlushing = false; 143var needsPaint = false; 144var shouldYieldForPaint = false; 145var disableYieldValue = false; 146 147function setDisableYieldValue(newValue) { 148 disableYieldValue = newValue; 149} 150 151function advanceTimers(currentTime) { 152 // Check for tasks that are no longer delayed and add them to the queue. 153 var timer = peek(timerQueue); 154 155 while (timer !== null) { 156 if (timer.callback === null) { 157 // Timer was cancelled. 158 pop(timerQueue); 159 } else if (timer.startTime <= currentTime) { 160 // Timer fired. Transfer to the task queue. 161 pop(timerQueue); 162 timer.sortIndex = timer.expirationTime; 163 push(taskQueue, timer); 164 } else { 165 // Remaining timers are pending. 166 return; 167 } 168 169 timer = peek(timerQueue); 170 } 171} 172 173function handleTimeout(currentTime) { 174 isHostTimeoutScheduled = false; 175 advanceTimers(currentTime); 176 177 if (!isHostCallbackScheduled) { 178 if (peek(taskQueue) !== null) { 179 isHostCallbackScheduled = true; 180 requestHostCallback(flushWork); 181 } else { 182 var firstTimer = peek(timerQueue); 183 184 if (firstTimer !== null) { 185 requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime); 186 } 187 } 188 } 189} 190 191function flushWork(hasTimeRemaining, initialTime) { 192 193 194 isHostCallbackScheduled = false; 195 196 if (isHostTimeoutScheduled) { 197 // We scheduled a timeout but it's no longer needed. Cancel it. 198 isHostTimeoutScheduled = false; 199 cancelHostTimeout(); 200 } 201 202 isPerformingWork = true; 203 var previousPriorityLevel = currentPriorityLevel; 204 205 try { 206 if (enableProfiling) { 207 try { 208 return workLoop(hasTimeRemaining, initialTime); 209 } catch (error) { 210 if (currentTask !== null) { 211 var currentTime = getCurrentTime(); 212 markTaskErrored(currentTask, currentTime); 213 currentTask.isQueued = false; 214 } 215 216 throw error; 217 } 218 } else { 219 // No catch in prod code path. 220 return workLoop(hasTimeRemaining, initialTime); 221 } 222 } finally { 223 currentTask = null; 224 currentPriorityLevel = previousPriorityLevel; 225 isPerformingWork = false; 226 } 227} 228 229function workLoop(hasTimeRemaining, initialTime) { 230 var currentTime = initialTime; 231 advanceTimers(currentTime); 232 currentTask = peek(taskQueue); 233 234 while (currentTask !== null && !(enableSchedulerDebugging )) { 235 if (currentTask.expirationTime > currentTime && (!hasTimeRemaining || shouldYieldToHost())) { 236 // This currentTask hasn't expired, and we've reached the deadline. 237 break; 238 } 239 240 var callback = currentTask.callback; 241 242 if (typeof callback === 'function') { 243 currentTask.callback = null; 244 currentPriorityLevel = currentTask.priorityLevel; 245 var didUserCallbackTimeout = currentTask.expirationTime <= currentTime; 246 247 var continuationCallback = callback(didUserCallbackTimeout); 248 currentTime = getCurrentTime(); 249 250 if (typeof continuationCallback === 'function') { 251 currentTask.callback = continuationCallback; 252 } else { 253 254 if (currentTask === peek(taskQueue)) { 255 pop(taskQueue); 256 } 257 } 258 259 advanceTimers(currentTime); 260 } else { 261 pop(taskQueue); 262 } 263 264 currentTask = peek(taskQueue); 265 } // Return whether there's additional work 266 267 268 if (currentTask !== null) { 269 return true; 270 } else { 271 var firstTimer = peek(timerQueue); 272 273 if (firstTimer !== null) { 274 requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime); 275 } 276 277 return false; 278 } 279} 280 281function unstable_runWithPriority(priorityLevel, eventHandler) { 282 switch (priorityLevel) { 283 case ImmediatePriority: 284 case UserBlockingPriority: 285 case NormalPriority: 286 case LowPriority: 287 case IdlePriority: 288 break; 289 290 default: 291 priorityLevel = NormalPriority; 292 } 293 294 var previousPriorityLevel = currentPriorityLevel; 295 currentPriorityLevel = priorityLevel; 296 297 try { 298 return eventHandler(); 299 } finally { 300 currentPriorityLevel = previousPriorityLevel; 301 } 302} 303 304function unstable_next(eventHandler) { 305 var priorityLevel; 306 307 switch (currentPriorityLevel) { 308 case ImmediatePriority: 309 case UserBlockingPriority: 310 case NormalPriority: 311 // Shift down to normal priority 312 priorityLevel = NormalPriority; 313 break; 314 315 default: 316 // Anything lower than normal priority should remain at the current level. 317 priorityLevel = currentPriorityLevel; 318 break; 319 } 320 321 var previousPriorityLevel = currentPriorityLevel; 322 currentPriorityLevel = priorityLevel; 323 324 try { 325 return eventHandler(); 326 } finally { 327 currentPriorityLevel = previousPriorityLevel; 328 } 329} 330 331function unstable_wrapCallback(callback) { 332 var parentPriorityLevel = currentPriorityLevel; 333 return function () { 334 // This is a fork of runWithPriority, inlined for performance. 335 var previousPriorityLevel = currentPriorityLevel; 336 currentPriorityLevel = parentPriorityLevel; 337 338 try { 339 return callback.apply(this, arguments); 340 } finally { 341 currentPriorityLevel = previousPriorityLevel; 342 } 343 }; 344} 345 346function unstable_scheduleCallback(priorityLevel, callback, options) { 347 var currentTime = getCurrentTime(); 348 var startTime; 349 350 if (typeof options === 'object' && options !== null) { 351 var delay = options.delay; 352 353 if (typeof delay === 'number' && delay > 0) { 354 startTime = currentTime + delay; 355 } else { 356 startTime = currentTime; 357 } 358 } else { 359 startTime = currentTime; 360 } 361 362 var timeout; 363 364 switch (priorityLevel) { 365 case ImmediatePriority: 366 timeout = IMMEDIATE_PRIORITY_TIMEOUT; 367 break; 368 369 case UserBlockingPriority: 370 timeout = USER_BLOCKING_PRIORITY_TIMEOUT; 371 break; 372 373 case IdlePriority: 374 timeout = IDLE_PRIORITY_TIMEOUT; 375 break; 376 377 case LowPriority: 378 timeout = LOW_PRIORITY_TIMEOUT; 379 break; 380 381 case NormalPriority: 382 default: 383 timeout = NORMAL_PRIORITY_TIMEOUT; 384 break; 385 } 386 387 var expirationTime = startTime + timeout; 388 var newTask = { 389 id: taskIdCounter++, 390 callback: callback, 391 priorityLevel: priorityLevel, 392 startTime: startTime, 393 expirationTime: expirationTime, 394 sortIndex: -1 395 }; 396 397 if (startTime > currentTime) { 398 // This is a delayed task. 399 newTask.sortIndex = startTime; 400 push(timerQueue, newTask); 401 402 if (peek(taskQueue) === null && newTask === peek(timerQueue)) { 403 // All tasks are delayed, and this is the task with the earliest delay. 404 if (isHostTimeoutScheduled) { 405 // Cancel an existing timeout. 406 cancelHostTimeout(); 407 } else { 408 isHostTimeoutScheduled = true; 409 } // Schedule a timeout. 410 411 412 requestHostTimeout(handleTimeout, startTime - currentTime); 413 } 414 } else { 415 newTask.sortIndex = expirationTime; 416 push(taskQueue, newTask); 417 // wait until the next time we yield. 418 419 420 if (!isHostCallbackScheduled && !isPerformingWork) { 421 isHostCallbackScheduled = true; 422 requestHostCallback(flushWork); 423 } 424 } 425 426 return newTask; 427} 428 429function unstable_pauseExecution() { 430} 431 432function unstable_continueExecution() { 433 434 if (!isHostCallbackScheduled && !isPerformingWork) { 435 isHostCallbackScheduled = true; 436 requestHostCallback(flushWork); 437 } 438} 439 440function unstable_getFirstCallbackNode() { 441 return peek(taskQueue); 442} 443 444function unstable_cancelCallback(task) { 445 // remove from the queue because you can't remove arbitrary nodes from an 446 // array based heap, only the first one.) 447 448 449 task.callback = null; 450} 451 452function unstable_getCurrentPriorityLevel() { 453 return currentPriorityLevel; 454} 455 456function requestHostCallback(callback) { 457 scheduledCallback = callback; 458} 459 460function requestHostTimeout(callback, ms) { 461 scheduledTimeout = callback; 462 timeoutTime = currentMockTime + ms; 463} 464 465function cancelHostTimeout() { 466 scheduledTimeout = null; 467 timeoutTime = -1; 468} 469 470function shouldYieldToHost() { 471 if (expectedNumberOfYields === 0 && yieldedValues === null || expectedNumberOfYields !== -1 && yieldedValues !== null && yieldedValues.length >= expectedNumberOfYields || shouldYieldForPaint && needsPaint) { 472 // We yielded at least as many values as expected. Stop flushing. 473 didStop = true; 474 return true; 475 } 476 477 return false; 478} 479 480function getCurrentTime() { 481 return currentMockTime; 482} 483 484function forceFrameRate() {// No-op 485} 486 487function reset() { 488 if (isFlushing) { 489 throw new Error('Cannot reset while already flushing work.'); 490 } 491 492 currentMockTime = 0; 493 scheduledCallback = null; 494 scheduledTimeout = null; 495 timeoutTime = -1; 496 yieldedValues = null; 497 expectedNumberOfYields = -1; 498 didStop = false; 499 isFlushing = false; 500 needsPaint = false; 501} // Should only be used via an assertion helper that inspects the yielded values. 502 503 504function unstable_flushNumberOfYields(count) { 505 if (isFlushing) { 506 throw new Error('Already flushing work.'); 507 } 508 509 if (scheduledCallback !== null) { 510 var cb = scheduledCallback; 511 expectedNumberOfYields = count; 512 isFlushing = true; 513 514 try { 515 var hasMoreWork = true; 516 517 do { 518 hasMoreWork = cb(true, currentMockTime); 519 } while (hasMoreWork && !didStop); 520 521 if (!hasMoreWork) { 522 scheduledCallback = null; 523 } 524 } finally { 525 expectedNumberOfYields = -1; 526 didStop = false; 527 isFlushing = false; 528 } 529 } 530} 531 532function unstable_flushUntilNextPaint() { 533 if (isFlushing) { 534 throw new Error('Already flushing work.'); 535 } 536 537 if (scheduledCallback !== null) { 538 var cb = scheduledCallback; 539 shouldYieldForPaint = true; 540 needsPaint = false; 541 isFlushing = true; 542 543 try { 544 var hasMoreWork = true; 545 546 do { 547 hasMoreWork = cb(true, currentMockTime); 548 } while (hasMoreWork && !didStop); 549 550 if (!hasMoreWork) { 551 scheduledCallback = null; 552 } 553 } finally { 554 shouldYieldForPaint = false; 555 didStop = false; 556 isFlushing = false; 557 } 558 } 559} 560 561function unstable_flushExpired() { 562 if (isFlushing) { 563 throw new Error('Already flushing work.'); 564 } 565 566 if (scheduledCallback !== null) { 567 isFlushing = true; 568 569 try { 570 var hasMoreWork = scheduledCallback(false, currentMockTime); 571 572 if (!hasMoreWork) { 573 scheduledCallback = null; 574 } 575 } finally { 576 isFlushing = false; 577 } 578 } 579} 580 581function unstable_flushAllWithoutAsserting() { 582 // Returns false if no work was flushed. 583 if (isFlushing) { 584 throw new Error('Already flushing work.'); 585 } 586 587 if (scheduledCallback !== null) { 588 var cb = scheduledCallback; 589 isFlushing = true; 590 591 try { 592 var hasMoreWork = true; 593 594 do { 595 hasMoreWork = cb(true, currentMockTime); 596 } while (hasMoreWork); 597 598 if (!hasMoreWork) { 599 scheduledCallback = null; 600 } 601 602 return true; 603 } finally { 604 isFlushing = false; 605 } 606 } else { 607 return false; 608 } 609} 610 611function unstable_clearYields() { 612 if (yieldedValues === null) { 613 return []; 614 } 615 616 var values = yieldedValues; 617 yieldedValues = null; 618 return values; 619} 620 621function unstable_flushAll() { 622 if (yieldedValues !== null) { 623 throw new Error('Log is not empty. Assert on the log of yielded values before ' + 'flushing additional work.'); 624 } 625 626 unstable_flushAllWithoutAsserting(); 627 628 if (yieldedValues !== null) { 629 throw new Error('While flushing work, something yielded a value. Use an ' + 'assertion helper to assert on the log of yielded values, e.g. ' + 'expect(Scheduler).toFlushAndYield([...])'); 630 } 631} 632 633function unstable_yieldValue(value) { 634 // eslint-disable-next-line react-internal/no-production-logging 635 if (console.log.name === 'disabledLog' || disableYieldValue) { 636 // If console.log has been patched, we assume we're in render 637 // replaying and we ignore any values yielding in the second pass. 638 return; 639 } 640 641 if (yieldedValues === null) { 642 yieldedValues = [value]; 643 } else { 644 yieldedValues.push(value); 645 } 646} 647 648function unstable_advanceTime(ms) { 649 // eslint-disable-next-line react-internal/no-production-logging 650 if (console.log.name === 'disabledLog' || disableYieldValue) { 651 // If console.log has been patched, we assume we're in render 652 // replaying and we ignore any time advancing in the second pass. 653 return; 654 } 655 656 currentMockTime += ms; 657 658 if (scheduledTimeout !== null && timeoutTime <= currentMockTime) { 659 scheduledTimeout(currentMockTime); 660 timeoutTime = -1; 661 scheduledTimeout = null; 662 } 663} 664 665function requestPaint() { 666 needsPaint = true; 667} 668var unstable_Profiling = null; 669 670exports.reset = reset; 671exports.unstable_IdlePriority = IdlePriority; 672exports.unstable_ImmediatePriority = ImmediatePriority; 673exports.unstable_LowPriority = LowPriority; 674exports.unstable_NormalPriority = NormalPriority; 675exports.unstable_Profiling = unstable_Profiling; 676exports.unstable_UserBlockingPriority = UserBlockingPriority; 677exports.unstable_advanceTime = unstable_advanceTime; 678exports.unstable_cancelCallback = unstable_cancelCallback; 679exports.unstable_clearYields = unstable_clearYields; 680exports.unstable_continueExecution = unstable_continueExecution; 681exports.unstable_flushAll = unstable_flushAll; 682exports.unstable_flushAllWithoutAsserting = unstable_flushAllWithoutAsserting; 683exports.unstable_flushExpired = unstable_flushExpired; 684exports.unstable_flushNumberOfYields = unstable_flushNumberOfYields; 685exports.unstable_flushUntilNextPaint = unstable_flushUntilNextPaint; 686exports.unstable_forceFrameRate = forceFrameRate; 687exports.unstable_getCurrentPriorityLevel = unstable_getCurrentPriorityLevel; 688exports.unstable_getFirstCallbackNode = unstable_getFirstCallbackNode; 689exports.unstable_next = unstable_next; 690exports.unstable_now = getCurrentTime; 691exports.unstable_pauseExecution = unstable_pauseExecution; 692exports.unstable_requestPaint = requestPaint; 693exports.unstable_runWithPriority = unstable_runWithPriority; 694exports.unstable_scheduleCallback = unstable_scheduleCallback; 695exports.unstable_setDisableYieldValue = setDisableYieldValue; 696exports.unstable_shouldYield = shouldYieldToHost; 697exports.unstable_wrapCallback = unstable_wrapCallback; 698exports.unstable_yieldValue = unstable_yieldValue; 699 })(); 700}