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; | |