1. <!DOCTYPE html>
    
  2. <html style="width: 100%; height: 100%;">
    
  3. 
    
  4. <head>
    
  5.   <meta charset="utf-8">
    
  6.   <title>Scheduler Test Page</title>
    
  7.   <style>
    
  8.     .correct {
    
  9.       border: solid green 2px;
    
  10.     }
    
  11.     .incorrect {
    
  12.       border: dashed red 2px;
    
  13.     }
    
  14.   </style>
    
  15. </head>
    
  16. 
    
  17. <body>
    
  18.   <h1>Scheduler Fixture</h1>
    
  19.   <p>
    
  20.     This fixture is for manual testing purposes, and the patterns used in
    
  21.     implementing it should not be used as a model. This is mainly for anyone
    
  22.     working on making changes to the `schedule` module.
    
  23.   </p>
    
  24.   <h2>Tests:</h2>
    
  25.   <ol>
    
  26.     <li>
    
  27.       <button onClick="runTestOne()">Run Test 1</button>
    
  28.       <p>Calls the callback within the frame when not blocked:</p>
    
  29.       <div><b>Expected:</b></div>
    
  30.       <div id="test-1-expected">
    
  31.       </div>
    
  32.       <div> -------------------------------------------------</div>
    
  33.       <div> If you see the same above and below it's correct.
    
  34.         <div> -------------------------------------------------</div>
    
  35.         <div><b>Actual:</b></div>
    
  36.         <div id="test-1"></div>
    
  37.     </li>
    
  38.     <li>
    
  39.       <p>Accepts multiple callbacks and calls within frame when not blocked</p>
    
  40.       <button onClick="runTestTwo()">Run Test 2</button>
    
  41.       <div><b>Expected:</b></div>
    
  42.       <div id="test-2-expected">
    
  43.       </div>
    
  44.       <div> -------------------------------------------------</div>
    
  45.       <div> If you see the same above and below it's correct.
    
  46.         <div> -------------------------------------------------</div>
    
  47.         <div><b>Actual:</b></div>
    
  48.         <div id="test-2"></div>
    
  49.     </li>
    
  50.     <li>
    
  51.       <p>Schedules callbacks in correct order when they use scheduleCallback to schedule themselves</p>
    
  52.       <button onClick="runTestThree()">Run Test 3</button>
    
  53.       <div><b>Expected:</b></div>
    
  54.       <div id="test-3-expected">
    
  55.       </div>
    
  56.       <div> -------------------------------------------------</div>
    
  57.       <div> If you see the same above and below it's correct.
    
  58.         <div> -------------------------------------------------</div>
    
  59.         <div><b>Actual:</b></div>
    
  60.         <div id="test-3"></div>
    
  61.     </li>
    
  62.     <li>
    
  63.       <p>Calls timed out callbacks and then any more pending callbacks, defers others if time runs out</p>
    
  64.       <button onClick="runTestFour()">Run Test 4</button>
    
  65.       <div><b>Expected:</b></div>
    
  66.       <div id="test-4-expected">
    
  67.       </div>
    
  68.       <div> -------------------------------------------------</div>
    
  69.       <div> If you see the same above and below it's correct.
    
  70.         <div> -------------------------------------------------</div>
    
  71.         <div><b>Actual:</b></div>
    
  72.         <div id="test-4"></div>
    
  73.     </li>
    
  74.     <li>
    
  75.       <p>When some callbacks throw errors, still calls them all within the same frame</p>
    
  76.       <p><b>IMPORTANT:</b> Open the console when you run this! Inspect the logs there!</p>
    
  77.       <button onClick="runTestFive()">Run Test 5</button>
    
  78.     </li>
    
  79.     <li>
    
  80.       <p>When some callbacks throw errors <b> and some also time out</b>, still calls them all within the same frame</p>
    
  81.       <p><b>IMPORTANT:</b> Open the console when you run this! Inspect the logs there!</p>
    
  82.       <button onClick="runTestSix()">Run Test 6</button>
    
  83.     </li>
    
  84.     <li>
    
  85.       <p>Continues calling callbacks even when user switches away from this tab</p>
    
  86.       <button onClick="runTestSeven()">Run Test 7</button>
    
  87.       <div><b>Click the button above, observe the counter, then switch to
    
  88.           another tab and switch back:</b></div>
    
  89.       <div id="test-7">
    
  90.       </div>
    
  91.       <div> If the counter advanced while you were away from this tab, it's correct.</div>
    
  92.     </li>
    
  93.     <li>
    
  94.       <p>Can pause execution, dump scheduled callbacks, and continue where it left off</p>
    
  95.       <button onClick="runTestEight()">Run Test 8</button>
    
  96.       <div><b>Click the button above, press "continue" to finish the test after it pauses:</b></div>
    
  97.       <button onClick="continueTestEight()">continue</button>
    
  98.       <div><b>Expected:</b></div>
    
  99.       <div id="test-8-expected">
    
  100.       </div>
    
  101.       <div> -------------------------------------------------</div>
    
  102.       <div> If the test didn't progress until you hit "continue" and </div>
    
  103.       <div> you see the same above and below afterwards it's correct.
    
  104.         <div> -------------------------------------------------</div>
    
  105.         <div><b>Actual:</b></div>
    
  106.         <div id="test-8"></div>
    
  107.     </li>
    
  108.     <li>
    
  109.       <p>Can force a specific framerate</p>
    
  110.       <p><b>IMPORTANT:</b> This test may be flaky if other tests have been run in this js instance. To get a clean test refresh the page before running test 9</p>
    
  111.       <button onClick="runTestNine()">Run Test 9</button>
    
  112.       <div><b>Expected:</b></div>
    
  113.       <div id="test-9-expected">
    
  114.       </div>
    
  115.       <div> -------------------------------------------------</div>
    
  116.       <div> If you see the same above and below it's correct.
    
  117.         <div> -------------------------------------------------</div>
    
  118.         <div><b>Actual:</b></div>
    
  119.         <div id="test-9"></div>
    
  120.       </div>
    
  121.     </li>
    
  122.     <li>
    
  123.       <p>Runs scheduled JS work for 99% of the frame time when nothing else is using the thread.</p>
    
  124.       <p><b>NOTE:</b> Try this test both when nothing else is running and when something is using the compositor thread in another visible tab with video or <a href="https://www.shadertoy.com/view/MtffDX">WebGL content</a> (Shift+Click).</p>
    
  125.       <button onClick="runTestTen()">Run Test 10</button>
    
  126.       <div><b>Expected:</b></div>
    
  127.       <div id="test-10-expected">
    
  128.       </div>
    
  129.       <div> -------------------------------------------------</div>
    
  130.       <div> If you see the same above and below it's correct.
    
  131.         <div> -------------------------------------------------</div>
    
  132.         <div><b>Actual:</b></div>
    
  133.         <div id="test-10"></div>
    
  134.       </div>
    
  135.     </li>
    
  136.     <li>
    
  137.       <p>Runs scheduled JS work more than 95% of the frame time when inserting DOM nodes.</p>
    
  138.       <p><b>NOTE:</b> Try this test both when nothing else is running and when something is using the compositor thread in another visible tab with video or <a href="https://www.shadertoy.com/view/MtffDX">WebGL content</a> (Shift+Click).</p>
    
  139.       <button onClick="runTestEleven()">Run Test 11</button>
    
  140.       <div><b>Expected:</b></div>
    
  141.       <div id="test-11-expected">
    
  142.       </div>
    
  143.       <div> -------------------------------------------------</div>
    
  144.       <div> If you see the same above and below it's correct.
    
  145.         <div> -------------------------------------------------</div>
    
  146.         <div><b>Actual:</b></div>
    
  147.         <div id="test-11"></div>
    
  148.       </div>
    
  149.     </li>
    
  150.   </ol>
    
  151.   <script src="../../build/oss-experimental/react/umd/react.production.min.js"></script>
    
  152.   <script src="../../build/oss-experimental/scheduler/umd/scheduler.production.min.js"></script>
    
  153.   <script src="https://unpkg.com/babel-standalone@6/babel.js"></script>
    
  154.   <script type="text/babel">
    
  155. const {
    
  156.   unstable_scheduleCallback: scheduleCallback,
    
  157.   unstable_cancelCallback: cancelCallback,
    
  158.   unstable_now: now,
    
  159.   unstable_getFirstCallbackNode: getFirstCallbackNode,
    
  160.   unstable_pauseExecution: pauseExecution,
    
  161.   unstable_continueExecution: continueExecution,
    
  162.   unstable_forceFrameRate: forceFrameRate,
    
  163.   unstable_shouldYield: shouldYield,
    
  164.   unstable_NormalPriority: NormalPriority,
    
  165. } = Scheduler;
    
  166. function displayTestResult(testNumber) {
    
  167.   const expectationNode = document.getElementById('test-' + testNumber + '-expected');
    
  168.   const resultNode = document.getElementById('test-' + testNumber);
    
  169.   resultNode.innerHTML = latestResults[testNumber - 1].join('<br />');
    
  170.   expectationNode.innerHTML = expectedResults[testNumber - 1].join('<br />');
    
  171. }
    
  172. function clearTestResult(testNumber) {
    
  173.   const resultNode = document.getElementById('test-' + testNumber);
    
  174.   resultNode.innerHTML = '';
    
  175.   latestResults[testNumber - 1] = [];
    
  176. }
    
  177. function updateTestResult(testNumber, textToAddToResult) {
    
  178.   latestResults[testNumber - 1].push(textToAddToResult);
    
  179. };
    
  180. function checkTestResult(testNumber) {
    
  181. 
    
  182.   let correct = true;
    
  183.   const expected = expectedResults[testNumber - 1]; // zero indexing
    
  184.   const result = latestResults[testNumber - 1]; // zero indexing
    
  185.   if (expected.length !== result.length) {
    
  186.     correct = false;
    
  187.   } else {
    
  188.     for (let i = 0, len = expected.length; i < len; i++) {
    
  189.       if (expected[i] !== result[i]) {
    
  190.         correct = false;
    
  191.         break;
    
  192.       }
    
  193.     }
    
  194.   }
    
  195.   const currentClass = correct ? 'correct' : 'incorrect';
    
  196.   const previousClass = correct ? 'incorrect' : 'correct';
    
  197.   document.getElementById('test-' + testNumber).classList.remove(previousClass);
    
  198.   document.getElementById('test-' + testNumber).classList.add(currentClass);
    
  199. }
    
  200. function logWhenFramesStart(testNumber, cb) {
    
  201.   requestAnimationFrame(() => {
    
  202.     updateTestResult(testNumber, 'frame 1 started');
    
  203.     requestAnimationFrame(() => {
    
  204.       updateTestResult(testNumber, 'frame 2 started');
    
  205.       requestAnimationFrame(() => {
    
  206.         updateTestResult(testNumber, 'frame 3 started... we stop counting now.');
    
  207.         cb();
    
  208.       });
    
  209.     });
    
  210.   });
    
  211. }
    
  212. // push in results when we run the test
    
  213. const latestResults = [
    
  214.   // test 1
    
  215.   [
    
  216.   ],
    
  217.   // test 2
    
  218.   [
    
  219.   ],
    
  220.   // test 3
    
  221.   [
    
  222.   ],
    
  223.   // test 4
    
  224.   [
    
  225.   ],
    
  226.   // test 5
    
  227.   [
    
  228.   ],
    
  229. ];
    
  230. 
    
  231. const expectedResults = [
    
  232.   // test 1
    
  233.   [
    
  234.     'scheduled Cb1',
    
  235.     'frame 1 started',
    
  236.     'cb1 called with argument of false',
    
  237.     'frame 2 started',
    
  238.     'frame 3 started... we stop counting now.',
    
  239.   ],
    
  240.   // test 2
    
  241.   [
    
  242.     'scheduled CbA',
    
  243.     'scheduled CbB',
    
  244.     'frame 1 started',
    
  245.     'cbA called with argument of false',
    
  246.     'cbB called with argument of false',
    
  247.     'frame 2 started',
    
  248.     'frame 3 started... we stop counting now.',
    
  249.   ],
    
  250.   // test 3
    
  251.   [
    
  252.     'scheduled CbA',
    
  253.     'scheduled CbB',
    
  254.     'frame 1 started',
    
  255.     'scheduled CbA again',
    
  256.     'cbA0 called with argument of false',
    
  257.     'cbB called with argument of false',
    
  258.     'cbA1 called with argument of false',
    
  259.     'frame 2 started',
    
  260.     'frame 3 started... we stop counting now.',
    
  261.   ],
    
  262.   // test 4
    
  263.   [
    
  264.     'scheduled cbA',
    
  265.     'scheduled cbB',
    
  266.     'scheduled cbC',
    
  267.     'scheduled cbD',
    
  268.     'frame 1 started',
    
  269.     'cbC called with argument of {"didTimeout":true}',
    
  270.     'cbA called with argument of false',
    
  271.     'cbA running and taking some time',
    
  272.     'frame 2 started',
    
  273.     'cbB called with argument of false',
    
  274.     'cbD called with argument of false',
    
  275.     'frame 3 started... we stop counting now.',
    
  276.   ],
    
  277.   // test 5
    
  278.   [
    
  279.     // ... TODO
    
  280.   ],
    
  281.   [],
    
  282.   [],
    
  283.   // Test 8
    
  284.   [
    
  285.     'Queue size: 0.',
    
  286.     'Pausing... press continue to resume.',
    
  287.     'Queue size: 2.',
    
  288.     'Finishing...',
    
  289.     'Done!',
    
  290.   ],
    
  291.   // test 9
    
  292.   [
    
  293.     'Forcing new frame times...',
    
  294.     'Using new frame time!',
    
  295.     'Using new frame time!',
    
  296.     'Finished!',
    
  297.   ],
    
  298.   // test 10
    
  299.   [
    
  300.     'Running work for 10 seconds...',
    
  301.     'Ran scheduled work for >99% of the time.',
    
  302.   ],
    
  303.   // test 11
    
  304.   [
    
  305.     'Running work for 10 seconds...',
    
  306.     'Ran scheduled work for >95% of the time.',
    
  307.   ],
    
  308. ];
    
  309. function runTestOne() {
    
  310.   // Test 1
    
  311.   // Calls the callback with the frame when not blocked
    
  312.   clearTestResult(1);
    
  313.   const test1Log = [];
    
  314.   const cb1Arguments = [];
    
  315.   const cb1 = (x) => {
    
  316.     updateTestResult(1, 'cb1 called with argument of ' + JSON.stringify(x));
    
  317.   }
    
  318.   scheduleCallback(NormalPriority, cb1);
    
  319.   updateTestResult(1, 'scheduled Cb1');
    
  320.   logWhenFramesStart(1, () => {
    
  321.     displayTestResult(1);
    
  322.     checkTestResult(1);
    
  323.   });
    
  324. };
    
  325. 
    
  326. function runTestTwo() {
    
  327.   // Test 2
    
  328.   // accepts multiple callbacks and calls within frame when not blocked
    
  329.   clearTestResult(2);
    
  330.   const cbA = (x) => {
    
  331.     updateTestResult(2, 'cbA called with argument of ' + JSON.stringify(x));
    
  332.   }
    
  333.   const cbB = (x) => {
    
  334.     updateTestResult(2, 'cbB called with argument of ' + JSON.stringify(x));
    
  335.   }
    
  336.   scheduleCallback(NormalPriority, cbA);
    
  337.   updateTestResult(2, 'scheduled CbA');
    
  338.   scheduleCallback(NormalPriority, cbB);
    
  339.   updateTestResult(2, 'scheduled CbB');
    
  340.   logWhenFramesStart(2, () => {
    
  341.     displayTestResult(2);
    
  342.     checkTestResult(2);
    
  343.   });
    
  344. }
    
  345. 
    
  346. function runTestThree() {
    
  347.   // Test 3
    
  348.   // Schedules callbacks in correct order when they use scheduleCallback to schedule themselves
    
  349.   clearTestResult(3);
    
  350.   let callbackAIterations = 0;
    
  351.   const cbA = (x) => {
    
  352.     if (callbackAIterations < 1) {
    
  353.       scheduleCallback(NormalPriority, cbA);
    
  354.       updateTestResult(3, 'scheduled CbA again');
    
  355.     }
    
  356.     updateTestResult(3, 'cbA' + callbackAIterations + ' called with argument of ' + JSON.stringify(x));
    
  357.     callbackAIterations++;
    
  358.   }
    
  359.   const cbB = (x) => {
    
  360.     updateTestResult(3, 'cbB called with argument of ' + JSON.stringify(x));
    
  361.   }
    
  362.   scheduleCallback(NormalPriority, cbA);
    
  363.   updateTestResult(3, 'scheduled CbA');
    
  364.   scheduleCallback(NormalPriority, cbB);
    
  365.   updateTestResult(3, 'scheduled CbB');
    
  366.   logWhenFramesStart(3, () => {
    
  367.     displayTestResult(3);
    
  368.     checkTestResult(3);
    
  369.   });
    
  370. }
    
  371. 
    
  372. function waitForTimeToPass(timeInMs) {
    
  373.   const startTime = Date.now();
    
  374.   const endTime = startTime + timeInMs;
    
  375.   while (Date.now() < endTime) {
    
  376.     // wait...
    
  377.   }
    
  378. }
    
  379. 
    
  380. function runTestFour() {
    
  381.   // Test 4
    
  382.   // Calls timed out callbacks and then any more pending callbacks, defers others if time runs out
    
  383.   clearTestResult(4);
    
  384.   const cbA = (x) => {
    
  385.     updateTestResult(4, 'cbA called with argument of ' + JSON.stringify(x));
    
  386.     updateTestResult(4, 'cbA running and taking some time');
    
  387.     waitForTimeToPass(35);
    
  388.   }
    
  389.   const cbB = (x) => {
    
  390.     updateTestResult(4, 'cbB called with argument of ' + JSON.stringify(x));
    
  391.   }
    
  392.   const cbC = (x) => {
    
  393.     updateTestResult(4, 'cbC called with argument of ' + JSON.stringify(x));
    
  394.   }
    
  395.   const cbD = (x) => {
    
  396.     updateTestResult(4, 'cbD called with argument of ' + JSON.stringify(x));
    
  397.   }
    
  398.   scheduleCallback(NormalPriority, cbA); // won't time out
    
  399.   updateTestResult(4, 'scheduled cbA');
    
  400.   scheduleCallback(NormalPriority, cbB, {timeout: 100}); // times out later
    
  401.   updateTestResult(4, 'scheduled cbB');
    
  402.   scheduleCallback(NormalPriority, cbC, {timeout: 1}); // will time out fast
    
  403.   updateTestResult(4, 'scheduled cbC');
    
  404.   scheduleCallback(NormalPriority, cbD); // won't time out
    
  405.   updateTestResult(4, 'scheduled cbD');
    
  406. 
    
  407.   // should have run in order of C, A, B, D
    
  408. 
    
  409.   logWhenFramesStart(4, () => {
    
  410.     displayTestResult(4);
    
  411.     checkTestResult(4);
    
  412.   });
    
  413. 
    
  414. }
    
  415. 
    
  416. // Error handling
    
  417. 
    
  418. function runTestFive() {
    
  419.   // Test 5
    
  420.   // When some callbacks throw errors, still calls them all within the same frame
    
  421.   const cbA = (x) => {
    
  422.     console.log('cbA called with argument of ' + JSON.stringify(x));
    
  423.   }
    
  424.   const cbB = (x) => {
    
  425.     console.log('cbB called with argument of ' + JSON.stringify(x));
    
  426.     console.log('cbB is about to throw an error!');
    
  427.     throw new Error('error B');
    
  428.   }
    
  429.   const cbC = (x) => {
    
  430.     console.log('cbC called with argument of ' + JSON.stringify(x));
    
  431.   }
    
  432.   const cbD = (x) => {
    
  433.     console.log('cbD called with argument of ' + JSON.stringify(x));
    
  434.     console.log('cbD is about to throw an error!');
    
  435.     throw new Error('error D');
    
  436.   }
    
  437.   const cbE = (x) => {
    
  438.     console.log('cbE called with argument of ' + JSON.stringify(x));
    
  439.     console.log('This was the last callback! ------------------');
    
  440.   }
    
  441. 
    
  442.   console.log('We are aiming to roughly emulate the way ' +
    
  443.   '`requestAnimationFrame` handles errors from callbacks.');
    
  444. 
    
  445.   console.log('about to run the simulation of what it should look like...:');
    
  446. 
    
  447.   requestAnimationFrame(() => {
    
  448.     console.log('frame 1 started');
    
  449.     requestAnimationFrame(() => {
    
  450.       console.log('frame 2 started');
    
  451.       requestAnimationFrame(() => {
    
  452.         console.log('frame 3 started... we stop counting now.');
    
  453.         console.log('about to wait a moment and start this again but ' +
    
  454.         'with the scheduler instead of requestAnimationFrame');
    
  455.         setTimeout(runSchedulerCode, 1000);
    
  456.       });
    
  457.     });
    
  458.   });
    
  459.   requestAnimationFrame(cbA);
    
  460.   console.log('scheduled cbA');
    
  461.   requestAnimationFrame(cbB); // will throw error
    
  462.   console.log('scheduled cbB');
    
  463.   requestAnimationFrame(cbC);
    
  464.   console.log('scheduled cbC');
    
  465.   requestAnimationFrame(cbD); // will throw error
    
  466.   console.log('scheduled cbD');
    
  467.   requestAnimationFrame(cbE);
    
  468.   console.log('scheduled cbE');
    
  469. 
    
  470. 
    
  471.   function runSchedulerCode() {
    
  472.     console.log('-------------------------------------------------------------');
    
  473.     console.log('now lets see what it looks like using the scheduler...:');
    
  474.     requestAnimationFrame(() => {
    
  475.       console.log('frame 1 started');
    
  476.       requestAnimationFrame(() => {
    
  477.         console.log('frame 2 started');
    
  478.         requestAnimationFrame(() => {
    
  479.           console.log('frame 3 started... we stop counting now.');
    
  480.         });
    
  481.       });
    
  482.     });
    
  483.     scheduleCallback(NormalPriority, cbA);
    
  484.     console.log('scheduled cbA');
    
  485.     scheduleCallback(NormalPriority, cbB); // will throw error
    
  486.     console.log('scheduled cbB');
    
  487.     scheduleCallback(NormalPriority, cbC);
    
  488.     console.log('scheduled cbC');
    
  489.     scheduleCallback(NormalPriority, cbD); // will throw error
    
  490.     console.log('scheduled cbD');
    
  491.     scheduleCallback(NormalPriority, cbE);
    
  492.     console.log('scheduled cbE');
    
  493.   };
    
  494. }
    
  495. 
    
  496. function runTestSix() {
    
  497.   // Test 6
    
  498.   // When some callbacks throw errors, still calls them all within the same frame
    
  499.   const cbA = (x) => {
    
  500.     console.log('cbA called with argument of ' + JSON.stringify(x));
    
  501.     console.log('cbA is about to throw an error!');
    
  502.     throw new Error('error A');
    
  503.   }
    
  504.   const cbB = (x) => {
    
  505.     console.log('cbB called with argument of ' + JSON.stringify(x));
    
  506.   }
    
  507.   const cbC = (x) => {
    
  508.     console.log('cbC called with argument of ' + JSON.stringify(x));
    
  509.   }
    
  510.   const cbD = (x) => {
    
  511.     console.log('cbD called with argument of ' + JSON.stringify(x));
    
  512.     console.log('cbD is about to throw an error!');
    
  513.     throw new Error('error D');
    
  514.   }
    
  515.   const cbE = (x) => {
    
  516.     console.log('cbE called with argument of ' + JSON.stringify(x));
    
  517.     console.log('This was the last callback! ------------------');
    
  518.   }
    
  519. 
    
  520.   console.log('We are aiming to roughly emulate the way ' +
    
  521.   '`requestAnimationFrame` handles errors from callbacks.');
    
  522. 
    
  523.   console.log('about to run the simulation of what it should look like...:');
    
  524. 
    
  525.   requestAnimationFrame(() => {
    
  526.     console.log('frame 1 started');
    
  527.     requestAnimationFrame(() => {
    
  528.       console.log('frame 2 started');
    
  529.       requestAnimationFrame(() => {
    
  530.         console.log('frame 3 started... we stop counting now.');
    
  531.         console.log('about to wait a moment and start this again but ' +
    
  532.         'with the scheduler instead of requestAnimationFrame');
    
  533.         setTimeout(runSchedulerCode, 1000);
    
  534.       });
    
  535.     });
    
  536.   });
    
  537.   requestAnimationFrame(cbC);
    
  538.   console.log('scheduled cbC first; simulating timing out');
    
  539.   requestAnimationFrame(cbD); // will throw error
    
  540.   console.log('scheduled cbD first; simulating timing out');
    
  541.   requestAnimationFrame(cbE);
    
  542.   console.log('scheduled cbE first; simulating timing out');
    
  543.   requestAnimationFrame(cbA);
    
  544.   console.log('scheduled cbA'); // will throw error
    
  545.   requestAnimationFrame(cbB);
    
  546.   console.log('scheduled cbB');
    
  547. 
    
  548. 
    
  549.   function runSchedulerCode() {
    
  550.     console.log('-------------------------------------------------------------');
    
  551.     console.log('now lets see what it looks like using the scheduler...:');
    
  552.     requestAnimationFrame(() => {
    
  553.       console.log('frame 1 started');
    
  554.       requestAnimationFrame(() => {
    
  555.         console.log('frame 2 started');
    
  556.         requestAnimationFrame(() => {
    
  557.           console.log('frame 3 started... we stop counting now.');
    
  558.         });
    
  559.       });
    
  560.     });
    
  561.     scheduleCallback(NormalPriority, cbA);
    
  562.     console.log('scheduled cbA');
    
  563.     scheduleCallback(NormalPriority, cbB); // will throw error
    
  564.     console.log('scheduled cbB');
    
  565.     scheduleCallback(NormalPriority, cbC, {timeout: 1});
    
  566.     console.log('scheduled cbC');
    
  567.     scheduleCallback(NormalPriority, cbD, {timeout: 1}); // will throw error
    
  568.     console.log('scheduled cbD');
    
  569.     scheduleCallback(NormalPriority, cbE, {timeout: 1});
    
  570.     console.log('scheduled cbE');
    
  571.   };
    
  572. }
    
  573. 
    
  574. function runTestSeven() {
    
  575.   // Test 7
    
  576.   // Calls callbacks, continues calling them even when this tab is in the
    
  577.   // background
    
  578.   clearTestResult(7);
    
  579.   let counter = -1;
    
  580.   function incrementCounterAndScheduleNextCallback() {
    
  581.     const counterNode = document.getElementById('test-7');
    
  582.     counter++;
    
  583.     counterNode.innerHTML = counter;
    
  584.     waitForTimeToPass(100);
    
  585.     scheduleCallback(NormalPriority, incrementCounterAndScheduleNextCallback);
    
  586.   }
    
  587.   scheduleCallback(NormalPriority, incrementCounterAndScheduleNextCallback);
    
  588. }
    
  589. 
    
  590. function runTestEight() {
    
  591.   // Test 8
    
  592.   // Pauses execution, dumps the queue, and continues execution
    
  593.   clearTestResult(8);
    
  594. 
    
  595.   function countNodesInStack(firstCallbackNode) {
    
  596.     var node = firstCallbackNode;
    
  597.     var count = 0;
    
  598.     if (node !== null) {
    
  599.       do {
    
  600.         count = count + 1;
    
  601.         node = node.next;
    
  602.       } while (node !== firstCallbackNode);
    
  603.     }
    
  604.     return count;
    
  605.   }
    
  606. 
    
  607.   scheduleCallback(NormalPriority, () => {
    
  608. 
    
  609.     // size should be 0
    
  610.     updateTestResult(8, `Queue size: ${countNodesInStack(getFirstCallbackNode())}.`);
    
  611.     updateTestResult(8, 'Pausing... press continue to resume.');
    
  612.     pauseExecution();
    
  613. 
    
  614.     scheduleCallback(NormalPriority, function () {
    
  615.       updateTestResult(8, 'Finishing...');
    
  616.       displayTestResult(8);
    
  617.     })
    
  618.     scheduleCallback(NormalPriority, function () {
    
  619.       updateTestResult(8, 'Done!');
    
  620.       displayTestResult(8);
    
  621.       checkTestResult(8);
    
  622.     })
    
  623. 
    
  624.     // new size should be 2 now
    
  625.     updateTestResult(8, `Queue size: ${countNodesInStack(getFirstCallbackNode())}.`);
    
  626.     displayTestResult(8);
    
  627.   });
    
  628. }
    
  629. 
    
  630. function continueTestEight() {
    
  631.   continueExecution();
    
  632. }
    
  633. 
    
  634. function runTestNine() {
    
  635.   clearTestResult(9);
    
  636.   // We have this to make sure that the thing that goes right after it can get a full frame
    
  637.   var forceFrameFinish = () => {
    
  638.     while (!shouldYield()) {
    
  639.       waitForTimeToPass(1);
    
  640.     }
    
  641.     waitForTimeToPass(100);
    
  642.   }
    
  643.   scheduleCallback(NormalPriority, forceFrameFinish);
    
  644.   scheduleCallback(NormalPriority, () => {
    
  645.     var startTime = now();
    
  646.     while (!shouldYield()) {}
    
  647.     var initialFrameTime = now() - startTime;
    
  648.     var newFrameTime = (initialFrameTime * 2) > 60 ? (initialFrameTime * 2) : 60;
    
  649.     var newFrameRate = Math.floor(1000/newFrameTime);
    
  650.     updateTestResult(9, `Forcing new frame times...`);
    
  651.     displayTestResult(9);
    
  652.     forceFrameRate(newFrameRate);
    
  653.     var toSchedule = (again) => {
    
  654.       var startTime = now();
    
  655.       while (!shouldYield()) {}
    
  656.       var frameTime = now() - startTime;
    
  657.       if (frameTime >= (newFrameTime-8)) {
    
  658.         updateTestResult(9, `Using new frame time!`);
    
  659.       } else {
    
  660.         updateTestResult(9, `Failed to use new frame time. (off by ${newFrameTime - frameTime}ms)`);
    
  661.       }
    
  662.       displayTestResult(9);
    
  663.       if (again) {
    
  664.         scheduleCallback(NormalPriority, forceFrameFinish);
    
  665.         scheduleCallback(NormalPriority, () => {toSchedule(false);});
    
  666.       } else {
    
  667.         updateTestResult(9, `Finished!`);
    
  668.         forceFrameRate(0);
    
  669.         displayTestResult(9);
    
  670.         checkTestResult(9);
    
  671.       }
    
  672.     }
    
  673.     scheduleCallback(NormalPriority, forceFrameFinish);
    
  674.     scheduleCallback(NormalPriority, () => {toSchedule(true);});
    
  675.   });
    
  676. }
    
  677. 
    
  678. function runTestTen() {
    
  679.   clearTestResult(10);
    
  680.   updateTestResult(10, `Running work for 10 seconds...`);
    
  681.   var testStartTime = now();
    
  682.   var accumulatedWork = 0
    
  683.   function loop() {
    
  684.     var startTime = now();
    
  685.     while (!shouldYield()) {}
    
  686.     var endTime = now();
    
  687.     accumulatedWork += endTime - startTime;
    
  688.     var runTime = endTime - testStartTime;
    
  689.     if (runTime > 10000) {
    
  690.       updateTestResult(10, `Ran scheduled work for ${(100 * accumulatedWork / runTime).toFixed(2)}% of the time.`);
    
  691.       displayTestResult(10);
    
  692.       return;
    
  693.     }
    
  694.     scheduleCallback(NormalPriority, loop);
    
  695.   }
    
  696.   scheduleCallback(NormalPriority, loop);
    
  697. }
    
  698. 
    
  699. function runTestEleven() {
    
  700.   clearTestResult(11);
    
  701.   updateTestResult(11, `Running work for 10 seconds...`);
    
  702.   var testStartTime = now();
    
  703.   var lastInsertion = 0;
    
  704.   var accumulatedWork = 0
    
  705.   function loop() {
    
  706.     var startTime = now();
    
  707.     var timeSinceLastDOMInteraction = startTime - lastInsertion;
    
  708.     if (timeSinceLastDOMInteraction > 15) {
    
  709.       lastInsertion = startTime;
    
  710.       var node = document.createElement('div');
    
  711.       node.textContent = startTime;
    
  712.       document.body.appendChild(node);
    
  713.       document.body.clientHeight; // force layout
    
  714.     }
    
  715.     while (!shouldYield()) {}
    
  716.     var endTime = now();
    
  717.     accumulatedWork += endTime - startTime;
    
  718.     var runTime = endTime - testStartTime;
    
  719.     if (runTime > 10000) {
    
  720.       updateTestResult(11, `Ran scheduled work for ${(100 * accumulatedWork / runTime).toFixed(2)}% of the time.`);
    
  721.       displayTestResult(11);
    
  722.       return;
    
  723.     }
    
  724.     scheduleCallback(NormalPriority, loop);
    
  725.   }
    
  726.   scheduleCallback(NormalPriority, loop);
    
  727. }
    
  728. 
    
  729.     </script type="text/babel">
    
  730.   </body>
    
  731. </html>