94
});
95
};
96
97
+ scheduler.yield = function ({priority, signal}) {
98
+ const id = idCounter++;
99
+ log(`Yield ${id} [${priority === undefined ? '<default>' : priority}]`);
100
+ const controller = signal._controller;
101
+ let callback;
102
+
103
+ return {
104
+ then(cb) {
105
+ callback = cb;
106
+ return new Promise((resolve, reject) => {
107
+ taskQueue.set(controller, {id, callback, resolve, reject});
108
+ });
109
+ },
110
+ };
111
+ };
112
+
113
global.TaskController = class TaskController {
114
constructor() {
115
this.signal = {_controller: this};
194
'Task 0 Fired',
195
'A',
196
'Yield at 5ms',
181
- 'Post Task 1 [user-visible]',
197
+ 'Yield 1 [user-visible]',
198
]);
199
200
runtime.flushTasks();
337
338
// The continuation should be scheduled in a separate macrotask even
339
// though there's time remaining.
324
- 'Post Task 1 [user-visible]',
340
+ 'Yield 1 [user-visible]',
341
]);
342
343
// No time has elapsed
346
runtime.flushTasks();
347
runtime.assertLog(['Task 1 Fired', 'Continuation Task']);
348
});
349
+
350
+ describe('falls back to postTask for scheduling continuations when scheduler.yield is not available', () => {
351
+ beforeEach(() => {
352
+ delete global.scheduler.yield;
353
+ });
354
+
355
+ it('task with continuation', () => {
356
+ scheduleCallback(NormalPriority, () => {
357
+ runtime.log('A');
358
+ while (!Scheduler.unstable_shouldYield()) {
359
+ runtime.advanceTime(1);
360
+ }
361
+ runtime.log(`Yield at ${performance.now()}ms`);
362
+ return () => {
363
+ runtime.log('Continuation');
364
+ };
365
+ });
366
+ runtime.assertLog(['Post Task 0 [user-visible]']);
367
+
368
+ runtime.flushTasks();
369
+ runtime.assertLog([
370
+ 'Task 0 Fired',
371
+ 'A',
372
+ 'Yield at 5ms',
373
+ 'Post Task 1 [user-visible]',
374
+ ]);
375
+
376
+ runtime.flushTasks();
377
+ runtime.assertLog(['Task 1 Fired', 'Continuation']);
378
+ });
379
+
380
+ it('yielding continues in a new task regardless of how much time is remaining', () => {
381
+ scheduleCallback(NormalPriority, () => {
382
+ runtime.log('Original Task');
383
+ runtime.log('shouldYield: ' + shouldYield());
384
+ runtime.log('Return a continuation');
385
+ return () => {
386
+ runtime.log('Continuation Task');
387
+ };
388
+ });
389
+ runtime.assertLog(['Post Task 0 [user-visible]']);
390
+
391
+ runtime.flushTasks();
392
+ runtime.assertLog([
393
+ 'Task 0 Fired',
394
+ 'Original Task',
395
+ // Immediately before returning a continuation, `shouldYield` returns
396
+ // false, which means there must be time remaining in the frame.
397
+ 'shouldYield: false',
398
+ 'Return a continuation',
399
+
400
+ // The continuation should be scheduled in a separate macrotask even
401
+ // though there's time remaining.
402
+ 'Post Task 1 [user-visible]',
403
+ ]);
404
+
405
+ // No time has elapsed
406
+ expect(performance.now()).toBe(0);
407
+
408
+ runtime.flushTasks();
409
+ runtime.assertLog(['Task 1 Fired', 'Continuation Task']);
410
+ });
411
+ });
412
});