Spaces:
Build error
Build error
| ; | |
| Object.defineProperty(exports, '__esModule', { | |
| value: true | |
| }); | |
| exports.default = void 0; | |
| var _FifoQueue = _interopRequireDefault(require('./FifoQueue')); | |
| var _types = require('./types'); | |
| function _interopRequireDefault(obj) { | |
| return obj && obj.__esModule ? obj : {default: obj}; | |
| } | |
| function _defineProperty(obj, key, value) { | |
| if (key in obj) { | |
| Object.defineProperty(obj, key, { | |
| value: value, | |
| enumerable: true, | |
| configurable: true, | |
| writable: true | |
| }); | |
| } else { | |
| obj[key] = value; | |
| } | |
| return obj; | |
| } | |
| class Farm { | |
| constructor(_numOfWorkers, _callback, options = {}) { | |
| var _options$workerSchedu, _options$taskQueue; | |
| _defineProperty(this, '_computeWorkerKey', void 0); | |
| _defineProperty(this, '_workerSchedulingPolicy', void 0); | |
| _defineProperty(this, '_cacheKeys', Object.create(null)); | |
| _defineProperty(this, '_locks', []); | |
| _defineProperty(this, '_offset', 0); | |
| _defineProperty(this, '_taskQueue', void 0); | |
| this._numOfWorkers = _numOfWorkers; | |
| this._callback = _callback; | |
| this._computeWorkerKey = options.computeWorkerKey; | |
| this._workerSchedulingPolicy = | |
| (_options$workerSchedu = options.workerSchedulingPolicy) !== null && | |
| _options$workerSchedu !== void 0 | |
| ? _options$workerSchedu | |
| : 'round-robin'; | |
| this._taskQueue = | |
| (_options$taskQueue = options.taskQueue) !== null && | |
| _options$taskQueue !== void 0 | |
| ? _options$taskQueue | |
| : new _FifoQueue.default(); | |
| } | |
| doWork(method, ...args) { | |
| const customMessageListeners = new Set(); | |
| const addCustomMessageListener = listener => { | |
| customMessageListeners.add(listener); | |
| return () => { | |
| customMessageListeners.delete(listener); | |
| }; | |
| }; | |
| const onCustomMessage = message => { | |
| customMessageListeners.forEach(listener => listener(message)); | |
| }; | |
| const promise = new Promise( // Bind args to this function so it won't reference to the parent scope. | |
| // This prevents a memory leak in v8, because otherwise the function will | |
| // retaine args for the closure. | |
| ((args, resolve, reject) => { | |
| const computeWorkerKey = this._computeWorkerKey; | |
| const request = [_types.CHILD_MESSAGE_CALL, false, method, args]; | |
| let worker = null; | |
| let hash = null; | |
| if (computeWorkerKey) { | |
| hash = computeWorkerKey.call(this, method, ...args); | |
| worker = hash == null ? null : this._cacheKeys[hash]; | |
| } | |
| const onStart = worker => { | |
| if (hash != null) { | |
| this._cacheKeys[hash] = worker; | |
| } | |
| }; | |
| const onEnd = (error, result) => { | |
| customMessageListeners.clear(); | |
| if (error) { | |
| reject(error); | |
| } else { | |
| resolve(result); | |
| } | |
| }; | |
| const task = { | |
| onCustomMessage, | |
| onEnd, | |
| onStart, | |
| request | |
| }; | |
| if (worker) { | |
| this._taskQueue.enqueue(task, worker.getWorkerId()); | |
| this._process(worker.getWorkerId()); | |
| } else { | |
| this._push(task); | |
| } | |
| }).bind(null, args) | |
| ); | |
| promise.UNSTABLE_onCustomMessage = addCustomMessageListener; | |
| return promise; | |
| } | |
| _process(workerId) { | |
| if (this._isLocked(workerId)) { | |
| return this; | |
| } | |
| const task = this._taskQueue.dequeue(workerId); | |
| if (!task) { | |
| return this; | |
| } | |
| if (task.request[1]) { | |
| throw new Error('Queue implementation returned processed task'); | |
| } // Reference the task object outside so it won't be retained by onEnd, | |
| // and other properties of the task object, such as task.request can be | |
| // garbage collected. | |
| const taskOnEnd = task.onEnd; | |
| const onEnd = (error, result) => { | |
| taskOnEnd(error, result); | |
| this._unlock(workerId); | |
| this._process(workerId); | |
| }; | |
| task.request[1] = true; | |
| this._lock(workerId); | |
| this._callback( | |
| workerId, | |
| task.request, | |
| task.onStart, | |
| onEnd, | |
| task.onCustomMessage | |
| ); | |
| return this; | |
| } | |
| _push(task) { | |
| this._taskQueue.enqueue(task); | |
| const offset = this._getNextWorkerOffset(); | |
| for (let i = 0; i < this._numOfWorkers; i++) { | |
| this._process((offset + i) % this._numOfWorkers); | |
| if (task.request[1]) { | |
| break; | |
| } | |
| } | |
| return this; | |
| } | |
| _getNextWorkerOffset() { | |
| switch (this._workerSchedulingPolicy) { | |
| case 'in-order': | |
| return 0; | |
| case 'round-robin': | |
| return this._offset++; | |
| } | |
| } | |
| _lock(workerId) { | |
| this._locks[workerId] = true; | |
| } | |
| _unlock(workerId) { | |
| this._locks[workerId] = false; | |
| } | |
| _isLocked(workerId) { | |
| return this._locks[workerId]; | |
| } | |
| } | |
| exports.default = Farm; | |