@loaders.gl/worker-utils
Version:
Utilities for running tasks on worker threads
132 lines (131 loc) • 4.33 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _globals = require("../env-utils/globals");
var _workerThread = _interopRequireDefault(require("./worker-thread"));
var _workerJob = _interopRequireDefault(require("./worker-job"));
class WorkerPool {
static isSupported() {
return _workerThread.default.isSupported();
}
constructor(props) {
(0, _defineProperty2.default)(this, "name", 'unnamed');
(0, _defineProperty2.default)(this, "source", void 0);
(0, _defineProperty2.default)(this, "url", void 0);
(0, _defineProperty2.default)(this, "maxConcurrency", 1);
(0, _defineProperty2.default)(this, "maxMobileConcurrency", 1);
(0, _defineProperty2.default)(this, "onDebug", () => {});
(0, _defineProperty2.default)(this, "reuseWorkers", true);
(0, _defineProperty2.default)(this, "props", {});
(0, _defineProperty2.default)(this, "jobQueue", []);
(0, _defineProperty2.default)(this, "idleQueue", []);
(0, _defineProperty2.default)(this, "count", 0);
(0, _defineProperty2.default)(this, "isDestroyed", false);
this.source = props.source;
this.url = props.url;
this.setProps(props);
}
destroy() {
this.idleQueue.forEach(worker => worker.destroy());
this.isDestroyed = true;
}
setProps(props) {
this.props = {
...this.props,
...props
};
if (props.name !== undefined) {
this.name = props.name;
}
if (props.maxConcurrency !== undefined) {
this.maxConcurrency = props.maxConcurrency;
}
if (props.maxMobileConcurrency !== undefined) {
this.maxMobileConcurrency = props.maxMobileConcurrency;
}
if (props.reuseWorkers !== undefined) {
this.reuseWorkers = props.reuseWorkers;
}
if (props.onDebug !== undefined) {
this.onDebug = props.onDebug;
}
}
async startJob(name) {
let onMessage = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : (job, type, data) => job.done(data);
let onError = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : (job, error) => job.error(error);
const startPromise = new Promise(onStart => {
this.jobQueue.push({
name,
onMessage,
onError,
onStart
});
return this;
});
this._startQueuedJob();
return await startPromise;
}
async _startQueuedJob() {
if (!this.jobQueue.length) {
return;
}
const workerThread = this._getAvailableWorker();
if (!workerThread) {
return;
}
const queuedJob = this.jobQueue.shift();
if (queuedJob) {
this.onDebug({
message: 'Starting job',
name: queuedJob.name,
workerThread,
backlog: this.jobQueue.length
});
const job = new _workerJob.default(queuedJob.name, workerThread);
workerThread.onMessage = data => queuedJob.onMessage(job, data.type, data.payload);
workerThread.onError = error => queuedJob.onError(job, error);
queuedJob.onStart(job);
try {
await job.result;
} finally {
this.returnWorkerToQueue(workerThread);
}
}
}
returnWorkerToQueue(worker) {
const shouldDestroyWorker = this.isDestroyed || !this.reuseWorkers || this.count > this._getMaxConcurrency();
if (shouldDestroyWorker) {
worker.destroy();
this.count--;
} else {
this.idleQueue.push(worker);
}
if (!this.isDestroyed) {
this._startQueuedJob();
}
}
_getAvailableWorker() {
if (this.idleQueue.length > 0) {
return this.idleQueue.shift() || null;
}
if (this.count < this._getMaxConcurrency()) {
this.count++;
const name = "".concat(this.name.toLowerCase(), " (#").concat(this.count, " of ").concat(this.maxConcurrency, ")");
return new _workerThread.default({
name,
source: this.source,
url: this.url
});
}
return null;
}
_getMaxConcurrency() {
return _globals.isMobile ? this.maxMobileConcurrency : this.maxConcurrency;
}
}
exports.default = WorkerPool;
//# sourceMappingURL=worker-pool.js.map