| 'use strict'; |
| |
| Object.defineProperty(exports, '__esModule', { |
| value: true |
| }); |
| exports.default = void 0; |
| |
| var _types = require('./types'); |
| |
| 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, computeWorkerKey) { |
| _defineProperty(this, '_computeWorkerKey', void 0); |
| |
| _defineProperty(this, '_cacheKeys', void 0); |
| |
| _defineProperty(this, '_callback', void 0); |
| |
| _defineProperty(this, '_last', void 0); |
| |
| _defineProperty(this, '_locks', void 0); |
| |
| _defineProperty(this, '_numOfWorkers', void 0); |
| |
| _defineProperty(this, '_offset', void 0); |
| |
| _defineProperty(this, '_queue', void 0); |
| |
| this._cacheKeys = Object.create(null); |
| this._callback = callback; |
| this._last = []; |
| this._locks = []; |
| this._numOfWorkers = numOfWorkers; |
| this._offset = 0; |
| this._queue = []; |
| |
| if (computeWorkerKey) { |
| this._computeWorkerKey = computeWorkerKey; |
| } |
| } |
| |
| 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((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._enqueue(task, worker.getWorkerId()); |
| } else { |
| this._push(task); |
| } |
| }); |
| promise.UNSTABLE_onCustomMessage = addCustomMessageListener; |
| return promise; |
| } |
| |
| _getNextTask(workerId) { |
| let queueHead = this._queue[workerId]; |
| |
| while (queueHead && queueHead.task.request[1]) { |
| queueHead = queueHead.next || null; |
| } |
| |
| this._queue[workerId] = queueHead; |
| return queueHead && queueHead.task; |
| } |
| |
| _process(workerId) { |
| if (this._isLocked(workerId)) { |
| return this; |
| } |
| |
| const task = this._getNextTask(workerId); |
| |
| if (!task) { |
| return this; |
| } |
| |
| const onEnd = (error, result) => { |
| task.onEnd(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; |
| } |
| |
| _enqueue(task, workerId) { |
| const item = { |
| next: null, |
| task |
| }; |
| |
| if (task.request[1]) { |
| return this; |
| } |
| |
| if (this._queue[workerId]) { |
| this._last[workerId].next = item; |
| } else { |
| this._queue[workerId] = item; |
| } |
| |
| this._last[workerId] = item; |
| |
| this._process(workerId); |
| |
| return this; |
| } |
| |
| _push(task) { |
| for (let i = 0; i < this._numOfWorkers; i++) { |
| this._enqueue(task, (this._offset + i) % this._numOfWorkers); |
| } |
| |
| this._offset++; |
| return this; |
| } |
| |
| _lock(workerId) { |
| this._locks[workerId] = true; |
| } |
| |
| _unlock(workerId) { |
| this._locks[workerId] = false; |
| } |
| |
| _isLocked(workerId) { |
| return this._locks[workerId]; |
| } |
| } |
| |
| exports.default = Farm; |