UNPKG

3.51 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', {
4 value: true
5});
6exports.default = void 0;
7
8var _types = require('./types');
9
10function _defineProperty(obj, key, value) {
11 if (key in obj) {
12 Object.defineProperty(obj, key, {
13 value: value,
14 enumerable: true,
15 configurable: true,
16 writable: true
17 });
18 } else {
19 obj[key] = value;
20 }
21 return obj;
22}
23
24class Farm {
25 constructor(numOfWorkers, callback, computeWorkerKey) {
26 _defineProperty(this, '_computeWorkerKey', void 0);
27
28 _defineProperty(this, '_cacheKeys', void 0);
29
30 _defineProperty(this, '_callback', void 0);
31
32 _defineProperty(this, '_last', void 0);
33
34 _defineProperty(this, '_locks', void 0);
35
36 _defineProperty(this, '_numOfWorkers', void 0);
37
38 _defineProperty(this, '_offset', void 0);
39
40 _defineProperty(this, '_queue', void 0);
41
42 this._cacheKeys = Object.create(null);
43 this._callback = callback;
44 this._last = [];
45 this._locks = [];
46 this._numOfWorkers = numOfWorkers;
47 this._offset = 0;
48 this._queue = [];
49
50 if (computeWorkerKey) {
51 this._computeWorkerKey = computeWorkerKey;
52 }
53 }
54
55 doWork(method, ...args) {
56 return new Promise((resolve, reject) => {
57 const computeWorkerKey = this._computeWorkerKey;
58 const request = [_types.CHILD_MESSAGE_CALL, false, method, args];
59 let worker = null;
60 let hash = null;
61
62 if (computeWorkerKey) {
63 hash = computeWorkerKey.call(this, method, ...args);
64 worker = hash == null ? null : this._cacheKeys[hash];
65 }
66
67 const onStart = worker => {
68 if (hash != null) {
69 this._cacheKeys[hash] = worker;
70 }
71 };
72
73 const onEnd = (error, result) => {
74 if (error) {
75 reject(error);
76 } else {
77 resolve(result);
78 }
79 };
80
81 const task = {
82 onEnd,
83 onStart,
84 request
85 };
86
87 if (worker) {
88 this._enqueue(task, worker.getWorkerId());
89 } else {
90 this._push(task);
91 }
92 });
93 }
94
95 _getNextTask(workerId) {
96 let queueHead = this._queue[workerId];
97
98 while (queueHead && queueHead.task.request[1]) {
99 queueHead = queueHead.next || null;
100 }
101
102 this._queue[workerId] = queueHead;
103 return queueHead && queueHead.task;
104 }
105
106 _process(workerId) {
107 if (this._isLocked(workerId)) {
108 return this;
109 }
110
111 const task = this._getNextTask(workerId);
112
113 if (!task) {
114 return this;
115 }
116
117 const onEnd = (error, result) => {
118 task.onEnd(error, result);
119
120 this._unlock(workerId);
121
122 this._process(workerId);
123 };
124
125 task.request[1] = true;
126
127 this._lock(workerId);
128
129 this._callback(workerId, task.request, task.onStart, onEnd);
130
131 return this;
132 }
133
134 _enqueue(task, workerId) {
135 const item = {
136 next: null,
137 task
138 };
139
140 if (task.request[1]) {
141 return this;
142 }
143
144 if (this._queue[workerId]) {
145 this._last[workerId].next = item;
146 } else {
147 this._queue[workerId] = item;
148 }
149
150 this._last[workerId] = item;
151
152 this._process(workerId);
153
154 return this;
155 }
156
157 _push(task) {
158 for (let i = 0; i < this._numOfWorkers; i++) {
159 this._enqueue(task, (this._offset + i) % this._numOfWorkers);
160 }
161
162 this._offset++;
163 return this;
164 }
165
166 _lock(workerId) {
167 this._locks[workerId] = true;
168 }
169
170 _unlock(workerId) {
171 this._locks[workerId] = false;
172 }
173
174 _isLocked(workerId) {
175 return this._locks[workerId];
176 }
177}
178
179exports.default = Farm;