forked from RubenVerborgh/AsyncIterator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
taskscheduler.ts
40 lines (36 loc) · 1.3 KB
/
taskscheduler.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
const resolved = Promise.resolve(undefined);
// Returns a function that asynchronously schedules a task
export function createTaskScheduler() : TaskScheduler {
// Use or create a microtask scheduler
const scheduleMicrotask = typeof queueMicrotask === 'function' ?
queueMicrotask : (task: Task) => resolved.then(task);
// Use or create a macrotask scheduler
const scheduleMacrotask = typeof setImmediate === 'function' ?
setImmediate : (task: Task) => setTimeout(task, 0);
// Interrupt with a macrotask every once in a while to avoid freezing
let i = 0;
let queue: Task[] | null = null;
return (task: Task) => {
// Tasks are currently being queued to avoid freezing
if (queue !== null)
queue.push(task);
// Tasks are being scheduled normally as microtasks
else if (++i < 100)
scheduleMicrotask(task);
// A macrotask interruption is needed
else {
// Hold all tasks in a queue, and reschedule them after a macrotask
queue = [ task ];
scheduleMacrotask(() => {
// Work through the queue
for (const queued of queue!)
scheduleMicrotask(queued);
queue = null;
// Reset the interruption schedule
i = 0;
});
}
}
}
export type Task = () => void;
export type TaskScheduler = (task: Task) => void;