yqueue
Version:
Yet another concurrent task queue
58 lines • 2.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.YQueue = exports.DEFAULT_QUEUE_CONCURRENCY = void 0;
const binary_heap_1 = require("./binary-heap");
const y_semaphore_1 = require("./y-semaphore");
exports.DEFAULT_QUEUE_CONCURRENCY = 10;
class YQueue {
constructor(options) {
var _a;
this.options = options;
this.onIdleWaits = [];
let concurrency = (_a = options === null || options === void 0 ? void 0 : options.concurrency) !== null && _a !== void 0 ? _a : exports.DEFAULT_QUEUE_CONCURRENCY;
if (!(concurrency >= 1))
concurrency = exports.DEFAULT_QUEUE_CONCURRENCY;
this.concurrency = concurrency;
this.semaphore = new y_semaphore_1.YSemaphore(concurrency);
this.onQueueLessThanWaits = new binary_heap_1.BinaryHeap((a, b) => a.threshold - b.threshold);
}
async run(fn, options) {
const acquired = await this.semaphore.acquire(options === null || options === void 0 ? void 0 : options.priority);
try {
return await fn();
}
finally {
this.semaphore.release(acquired);
if (this.semaphore.getAvailablePermits() === this.semaphore.permits) {
this.onIdleWaits.forEach(f => f());
this.onIdleWaits = [];
}
const queueLength = this.semaphore.getQueueLength();
for (;;) {
const next = this.onQueueLessThanWaits.peek();
if (next === null || queueLength >= next.threshold)
break;
next.ack();
this.onQueueLessThanWaits.removeMax();
}
}
}
add(fn, options) {
this.run(fn, options);
}
onIdle() {
if (this.semaphore.getAvailablePermits() === this.semaphore.permits) {
return Promise.resolve();
}
return new Promise(f => this.onIdleWaits.push(f));
}
onQueueSizeLessThan(size) {
if (this.semaphore.getQueueLength() < (size > 0 ? size : 1)) {
return Promise.resolve();
}
return new Promise(f => this.onQueueLessThanWaits.add({ ack: f, threshold: size }));
}
}
exports.YQueue = YQueue;
exports.default = YQueue;
//# sourceMappingURL=y-queue.js.map