This repository has been archived by the owner on Jul 30, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 62
/
Scheduler.ts
115 lines (91 loc) · 2.65 KB
/
Scheduler.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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import { Handle } from './interfaces';
import { QueueItem, queueTask } from './queue';
function getQueueHandle(item: QueueItem): Handle {
return {
destroy: function(this: Handle) {
this.destroy = function() {};
item.isActive = false;
item.callback = null;
}
};
}
export interface KwArgs {
deferWhileProcessing?: boolean;
queueFunction?: (callback: (...args: any[]) => any) => Handle;
}
export class Scheduler {
protected readonly _boundDispatch: () => void;
protected _deferred: QueueItem[] | null = null;
protected _isProcessing: boolean;
protected readonly _queue: QueueItem[];
protected _task: Handle | null = null;
/**
* Determines whether any callbacks registered during should be added to the current batch (`false`)
* or deferred until the next batch (`true`, default).
*/
deferWhileProcessing: boolean | undefined;
/**
* Allows users to specify the function that should be used to schedule callbacks.
* If no function is provided, then `queueTask` will be used.
*/
queueFunction: (callback: (...args: any[]) => any) => Handle;
protected _defer(callback: (...args: any[]) => void): Handle {
const item: QueueItem = {
isActive: true,
callback: callback
};
if (!this._deferred) {
this._deferred = [];
}
this._deferred.push(item);
return getQueueHandle(item);
}
protected _dispatch(): void {
this._isProcessing = true;
if (this._task) {
this._task.destroy();
this._task = null;
}
const queue = this._queue;
let item: QueueItem | undefined;
while ((item = queue.shift())) {
if (item.isActive && item.callback) {
item.callback();
}
}
this._isProcessing = false;
let deferred: QueueItem[] | null = this._deferred;
if (deferred && deferred.length) {
this._deferred = null;
let item: QueueItem | undefined;
while ((item = deferred.shift())) {
this._schedule(item);
}
}
}
protected _schedule(item: QueueItem): void {
if (!this._task) {
this._task = this.queueFunction(this._boundDispatch);
}
this._queue.push(item);
}
constructor(kwArgs?: KwArgs) {
this.deferWhileProcessing = kwArgs && 'deferWhileProcessing' in kwArgs ? kwArgs.deferWhileProcessing : true;
this.queueFunction = kwArgs && kwArgs.queueFunction ? kwArgs.queueFunction : queueTask;
this._boundDispatch = this._dispatch.bind(this);
this._isProcessing = false;
this._queue = [];
}
schedule(callback: (...args: any[]) => void): Handle {
if (this._isProcessing && this.deferWhileProcessing) {
return this._defer(callback);
}
const item: QueueItem = {
isActive: true,
callback: callback
};
this._schedule(item);
return getQueueHandle(item);
}
}
export default Scheduler;