Skip to content

Commit 1c2dd80

Browse files
πŸ› Handle null deadline in taskQueue requestIdleCallback (#4497)
1 parent dbaafeb commit 1c2dd80

File tree

2 files changed

+38
-3
lines changed

2 files changed

+38
-3
lines changed

β€Žpackages/core/src/tools/taskQueue.spec.tsβ€Ž

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { mockClock, mockRequestIdleCallback } from '../../test'
1+
import { mockClock, mockRequestIdleCallback, registerCleanupTask } from '../../test'
22
import { createTaskQueue, MAX_EXECUTION_TIME_ON_TIMEOUT } from './taskQueue'
33

44
describe('createTaskQueue', () => {
@@ -57,4 +57,37 @@ describe('createTaskQueue', () => {
5757
expect(task2).toHaveBeenCalled()
5858
expect(task3).not.toHaveBeenCalled()
5959
})
60+
61+
it('runs pending tasks when requestIdleCallback invokes the callback with no deadline', () => {
62+
const clock = mockClock()
63+
replaceRequestIdleCallbackWithPolyfillShim()
64+
65+
const taskQueue = createTaskQueue()
66+
const task1 = jasmine.createSpy('task1')
67+
const task2 = jasmine.createSpy('task2')
68+
const task3 = jasmine.createSpy('task3')
69+
70+
taskQueue.push(task1)
71+
taskQueue.push(task2)
72+
taskQueue.push(task3)
73+
74+
clock.tick(0)
75+
76+
expect(task1).toHaveBeenCalled()
77+
expect(task2).toHaveBeenCalled()
78+
expect(task3).toHaveBeenCalled()
79+
})
6080
})
81+
82+
function replaceRequestIdleCallbackWithPolyfillShim() {
83+
const originalRequestIdleCallback = window.requestIdleCallback
84+
const originalCancelIdleCallback = window.cancelIdleCallback
85+
// Reproduces `(cb) => setTimeout(cb, 0)` β€” invokes the callback with no argument.
86+
window.requestIdleCallback = ((cb: () => void) =>
87+
setTimeout(() => cb(), 0) as unknown as number) as typeof window.requestIdleCallback
88+
window.cancelIdleCallback = ((id: number) => clearTimeout(id)) as typeof window.cancelIdleCallback
89+
registerCleanupTask(() => {
90+
window.requestIdleCallback = originalRequestIdleCallback
91+
window.cancelIdleCallback = originalCancelIdleCallback
92+
})
93+
}

β€Žpackages/core/src/tools/taskQueue.tsβ€Ž

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ type Task = () => void
2828
export function createTaskQueue(): TaskQueue {
2929
const pendingTasks: Task[] = []
3030

31-
function run(deadline: IdleDeadline) {
31+
function run(deadline: IdleDeadline | null) {
3232
let executionTimeRemaining: () => number
33-
if (deadline.didTimeout) {
33+
// `deadline` can be null when `requestIdleCallback` is replaced by a page-injected polyfill
34+
// (e.g. `setTimeout(cb, 0)` in some WKWebViews) that invokes the callback with no argument.
35+
if (!deadline || deadline.didTimeout) {
3436
const start = performance.now()
3537
executionTimeRemaining = () => MAX_EXECUTION_TIME_ON_TIMEOUT - (performance.now() - start)
3638
} else {

0 commit comments

Comments
Β (0)