103 lines
3.9 KiB
JavaScript
103 lines
3.9 KiB
JavaScript
|
"use strict";
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
var tslib_1 = require("tslib");
|
||
|
var errors_1 = require("./errors");
|
||
|
var Semaphore = /** @class */ (function () {
|
||
|
function Semaphore(_maxConcurrency, _cancelError) {
|
||
|
if (_cancelError === void 0) { _cancelError = errors_1.E_CANCELED; }
|
||
|
this._maxConcurrency = _maxConcurrency;
|
||
|
this._cancelError = _cancelError;
|
||
|
this._queue = [];
|
||
|
this._waiters = [];
|
||
|
if (_maxConcurrency <= 0) {
|
||
|
throw new Error('semaphore must be initialized to a positive value');
|
||
|
}
|
||
|
this._value = _maxConcurrency;
|
||
|
}
|
||
|
Semaphore.prototype.acquire = function () {
|
||
|
var _this = this;
|
||
|
var locked = this.isLocked();
|
||
|
var ticketPromise = new Promise(function (resolve, reject) {
|
||
|
return _this._queue.push({ resolve: resolve, reject: reject });
|
||
|
});
|
||
|
if (!locked)
|
||
|
this._dispatch();
|
||
|
return ticketPromise;
|
||
|
};
|
||
|
Semaphore.prototype.runExclusive = function (callback) {
|
||
|
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
|
||
|
var _a, value, release;
|
||
|
return (0, tslib_1.__generator)(this, function (_b) {
|
||
|
switch (_b.label) {
|
||
|
case 0: return [4 /*yield*/, this.acquire()];
|
||
|
case 1:
|
||
|
_a = _b.sent(), value = _a[0], release = _a[1];
|
||
|
_b.label = 2;
|
||
|
case 2:
|
||
|
_b.trys.push([2, , 4, 5]);
|
||
|
return [4 /*yield*/, callback(value)];
|
||
|
case 3: return [2 /*return*/, _b.sent()];
|
||
|
case 4:
|
||
|
release();
|
||
|
return [7 /*endfinally*/];
|
||
|
case 5: return [2 /*return*/];
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
Semaphore.prototype.waitForUnlock = function () {
|
||
|
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
|
||
|
var waitPromise;
|
||
|
var _this = this;
|
||
|
return (0, tslib_1.__generator)(this, function (_a) {
|
||
|
if (!this.isLocked()) {
|
||
|
return [2 /*return*/, Promise.resolve()];
|
||
|
}
|
||
|
waitPromise = new Promise(function (resolve) { return _this._waiters.push({ resolve: resolve }); });
|
||
|
return [2 /*return*/, waitPromise];
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
Semaphore.prototype.isLocked = function () {
|
||
|
return this._value <= 0;
|
||
|
};
|
||
|
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */
|
||
|
Semaphore.prototype.release = function () {
|
||
|
if (this._maxConcurrency > 1) {
|
||
|
throw new Error('this method is unavailable on semaphores with concurrency > 1; use the scoped release returned by acquire instead');
|
||
|
}
|
||
|
if (this._currentReleaser) {
|
||
|
var releaser = this._currentReleaser;
|
||
|
this._currentReleaser = undefined;
|
||
|
releaser();
|
||
|
}
|
||
|
};
|
||
|
Semaphore.prototype.cancel = function () {
|
||
|
var _this = this;
|
||
|
this._queue.forEach(function (ticket) { return ticket.reject(_this._cancelError); });
|
||
|
this._queue = [];
|
||
|
};
|
||
|
Semaphore.prototype._dispatch = function () {
|
||
|
var _this = this;
|
||
|
var nextTicket = this._queue.shift();
|
||
|
if (!nextTicket)
|
||
|
return;
|
||
|
var released = false;
|
||
|
this._currentReleaser = function () {
|
||
|
if (released)
|
||
|
return;
|
||
|
released = true;
|
||
|
_this._value++;
|
||
|
_this._resolveWaiters();
|
||
|
_this._dispatch();
|
||
|
};
|
||
|
nextTicket.resolve([this._value--, this._currentReleaser]);
|
||
|
};
|
||
|
Semaphore.prototype._resolveWaiters = function () {
|
||
|
this._waiters.forEach(function (waiter) { return waiter.resolve(); });
|
||
|
this._waiters = [];
|
||
|
};
|
||
|
return Semaphore;
|
||
|
}());
|
||
|
exports.default = Semaphore;
|