-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
scheduler.js
97 lines (83 loc) · 2.81 KB
/
scheduler.js
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
// @flow
import ThrottledInvoker from './throttled_invoker.js';
import {bindAll, isWorker} from './util.js';
import {PerformanceUtils} from './performance.js';
class Scheduler {
tasks: { [number]: any };
taskQueue: Array<number>;
invoker: ThrottledInvoker;
nextId: number;
constructor() {
this.tasks = {};
this.taskQueue = [];
bindAll(['process'], this);
this.invoker = new ThrottledInvoker(this.process);
this.nextId = 0;
}
add(fn: () => void, metadata: Object) {
const id = this.nextId++;
this.tasks[id] = {fn, metadata, priority: getPriority(metadata), id};
this.taskQueue.push(id);
this.invoker.trigger();
return {
cancel: () => {
delete this.tasks[id];
}
};
}
process() {
const m = isWorker() ? PerformanceUtils.beginMeasure('workerTask') : undefined;
try {
this.taskQueue = this.taskQueue.filter(id => !!this.tasks[id]);
if (!this.taskQueue.length) {
return;
}
const id = this.pick();
if (id === null) return;
const task = this.tasks[id];
delete this.tasks[id];
// Schedule another process call if we know there's more to process _before_ invoking the
// current task. This is necessary so that processing continues even if the current task
// doesn't execute successfully.
if (this.taskQueue.length) {
this.invoker.trigger();
}
if (!task) {
// If the task ID doesn't have associated task data anymore, it was canceled.
return;
}
task.fn();
} finally {
if (m) PerformanceUtils.endMeasure(m);
}
}
pick() {
let minIndex = null;
let minPriority = Infinity;
for (let i = 0; i < this.taskQueue.length; i++) {
const id = this.taskQueue[i];
const task = this.tasks[id];
if (task.priority < minPriority) {
minPriority = task.priority;
minIndex = i;
}
}
if (minIndex === null) return null;
const id = this.taskQueue[minIndex];
this.taskQueue.splice(minIndex, 1);
return id;
}
remove() {
this.invoker.remove();
}
}
function getPriority({type, isSymbolTile, zoom}: Object) {
zoom = zoom || 0;
if (type === 'message') return 0;
if (type === 'maybePrepare' && !isSymbolTile) return 100 - zoom;
if (type === 'parseTile' && !isSymbolTile) return 200 - zoom;
if (type === 'parseTile' && isSymbolTile) return 300 - zoom;
if (type === 'maybePrepare' && isSymbolTile) return 400 - zoom;
return 500;
}
export default Scheduler;