-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathindex.js
More file actions
186 lines (174 loc) · 4.84 KB
/
index.js
File metadata and controls
186 lines (174 loc) · 4.84 KB
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
var ThreadPoolLite = (function () {
'use strict';
/**
*
* Our worker script
*
*/
const workerScript = `
(function workerScript(){
self.addEventListener('message', e => {
let result;
try{
result = eval(e.data);
}
catch(err){
setTimeout(function() { throw err; });
return;
}
if(result instanceof Promise){
result.then(x => {
self.postMessage(x);
}).catch(err => {
setTimeout(function() { throw err; });
})
} else {
self.postMessage(result);
}
})
})()`;
/**
*
* The url for our worker
*
*/
let url = URL.createObjectURL(new Blob([workerScript]));
class ThreadPoolLite{
/**
*
* Create a pool of workers, defaults to the amount of logical cores
* your hardware has.
*
* @param {Integer} workerCount
*/
constructor(workerCount = navigator.hardwareConcurrency){
/**
* The array of workers
*/
let workers = [];
let queue = [];
let tasks = new WeakMap();
/**
*
* Create all workers
*
*/
let toIdle = worker => {
/**
*
* Check for other tasks
*
*/
if(queue.length > 0){
/**
*
* Send another task to this worker
*
*/
let task = queue.shift();
worker.postMessage(task[0]);
tasks.set(worker, task[1]);
} else {
this.working = this.working.filter(e => worker !== e);
workers.push(worker);
tasks.set(worker, null);
}
}
for(let i = 0; i < workerCount; i++){
let worker = new Worker(url);
workers[i] = worker;
worker.onmessage = e => {
tasks.get(worker).resolve(e.data);
toIdle(worker);
}
worker.onerror = e => {
tasks.get(worker).reject(e.message);
toIdle(worker);
}
}
this.tasks = tasks;
this.worker = workers;
this.queue = queue;
this.working = [];
}
/**
*
* Runs(or enqueues, if no idle workers are available) a task.
*
* Tasks have scope of their own, and cannot access their parent scope.
*
*
* @param {Function} runnable - the task the worker receives
* @returns {Promise}
*/
run(runnable){
let deferred = {
resolve: null,
reject: null
};
let promise = new Promise((resolve, reject) => {
deferred.resolve = resolve;
deferred.reject = reject;
});
/**
*
* Enqueue the task
*
*/
this.queue.push(['('+runnable.toString()+')()', deferred]);
/**
*
* Check for idle workers
*
*/
if(this.worker.length > 0){
/**
*
* Get a worker
*
*/
let worker = this.worker.pop();
/**
*
* Send the task to the worker
*
*/
let task = this.queue.shift();
worker.postMessage(task[0]);
this.working.push(worker);
this.tasks.set(worker, task[1]);
}
return promise;
}
/**
*
* Terminates all workers
*
*/
terminate(){
for(let worker in this.working){
if(worker instanceof Worker){
worker.terminate();
}
}
this.working = [];
}
/**
*
* Get the active workers count
*
*/
getActiveCount(){
return this.working.length;
}
/**
*
* Get the idle workers count
*
*/
getIdleCount(){
return this.worker.length;
}
}
return ThreadPoolLite;
}());