@chriscdn/promise-semaphore 2.0.10 → 2.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -2
- package/__tests__/semaphore.test.ts +31 -8
- package/lib/index.d.ts +1 -6
- package/lib/promise-semaphore.cjs +1 -1
- package/lib/promise-semaphore.cjs.map +1 -1
- package/lib/promise-semaphore.modern.js +1 -1
- package/lib/promise-semaphore.modern.js.map +1 -1
- package/lib/promise-semaphore.module.js +1 -1
- package/lib/promise-semaphore.module.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +32 -11
package/README.md
CHANGED
|
@@ -51,7 +51,23 @@ semaphore.canAcquire([key]);
|
|
|
51
51
|
|
|
52
52
|
This synchronous method returns `true` if a lock can be immediately acquired, and `false` otherwise.
|
|
53
53
|
|
|
54
|
-
### `
|
|
54
|
+
### `count`
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
semaphore.count([key]);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
This synchronous function returns the current number of locks.
|
|
61
|
+
|
|
62
|
+
### `wait` method
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
semaphore.wait([key]);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
This asynchronous function resolves immediately if `count` is 0; otherwise, it resolves once `count` reaches 0.
|
|
69
|
+
|
|
70
|
+
### `request` method
|
|
55
71
|
|
|
56
72
|
```js
|
|
57
73
|
const results = await semaphore.request(fn [, key]);
|
|
@@ -68,7 +84,7 @@ try {
|
|
|
68
84
|
}
|
|
69
85
|
```
|
|
70
86
|
|
|
71
|
-
### `requestIfAvailable`
|
|
87
|
+
### `requestIfAvailable` method
|
|
72
88
|
|
|
73
89
|
```js
|
|
74
90
|
const results = await semaphore.requestIfAvailable(fn [, key]);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { describe, expect,
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
2
|
|
|
3
3
|
import Semaphore from "../src/index";
|
|
4
4
|
|
|
5
5
|
const pause = async (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
6
6
|
|
|
7
7
|
describe("All test", () => {
|
|
8
|
-
|
|
8
|
+
it("Acquire & Release Basic", async () => {
|
|
9
9
|
const semaphore = new Semaphore();
|
|
10
10
|
expect(semaphore.canAcquire()).toBe(true);
|
|
11
11
|
await semaphore.acquire();
|
|
@@ -17,7 +17,7 @@ describe("All test", () => {
|
|
|
17
17
|
expect(semaphore.count()).toBe(0);
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
it("Semaphore 1", async () => {
|
|
21
21
|
const semaphore = new Semaphore();
|
|
22
22
|
|
|
23
23
|
semaphore
|
|
@@ -36,7 +36,7 @@ describe("All test", () => {
|
|
|
36
36
|
expect(semaphore.canAcquire()).toBe(true);
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
it("Semaphore 2", async () => {
|
|
40
40
|
const semaphore = new Semaphore();
|
|
41
41
|
|
|
42
42
|
let tester = 0;
|
|
@@ -54,7 +54,7 @@ describe("All test", () => {
|
|
|
54
54
|
.finally(() => semaphore.release());
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
it("Semaphore 3", async () => {
|
|
58
58
|
const semaphore = new Semaphore(2);
|
|
59
59
|
|
|
60
60
|
let tester = 0;
|
|
@@ -85,7 +85,7 @@ describe("All test", () => {
|
|
|
85
85
|
expect(semaphore.canAcquire()).toBe(true);
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
it("Request 1", async () => {
|
|
89
89
|
const semaphore = new Semaphore();
|
|
90
90
|
|
|
91
91
|
let tester = 0;
|
|
@@ -105,7 +105,7 @@ describe("All test", () => {
|
|
|
105
105
|
});
|
|
106
106
|
});
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
it("Request 2", async () => {
|
|
109
109
|
const semaphore = new Semaphore(2);
|
|
110
110
|
|
|
111
111
|
let tester = 0;
|
|
@@ -125,7 +125,7 @@ describe("All test", () => {
|
|
|
125
125
|
});
|
|
126
126
|
});
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
it("Request 3", async () => {
|
|
129
129
|
const semaphore = new Semaphore(3);
|
|
130
130
|
|
|
131
131
|
let tester = 0;
|
|
@@ -145,3 +145,26 @@ describe("All test", () => {
|
|
|
145
145
|
});
|
|
146
146
|
});
|
|
147
147
|
});
|
|
148
|
+
|
|
149
|
+
describe("Wait TEST", () => {
|
|
150
|
+
const semaphore = new Semaphore(2);
|
|
151
|
+
|
|
152
|
+
it("Acquire & Release Basic", async () => {
|
|
153
|
+
let tester = 0;
|
|
154
|
+
|
|
155
|
+
semaphore
|
|
156
|
+
.acquire()
|
|
157
|
+
.then(() => pause(1000))
|
|
158
|
+
.then(() => (tester = 20))
|
|
159
|
+
.finally(() => semaphore.release());
|
|
160
|
+
|
|
161
|
+
semaphore
|
|
162
|
+
.acquire()
|
|
163
|
+
.then(() => pause(500))
|
|
164
|
+
.then(() => (tester = 10))
|
|
165
|
+
.finally(() => semaphore.release());
|
|
166
|
+
|
|
167
|
+
await semaphore.wait(); // WAIT for all tasks to finish
|
|
168
|
+
expect(tester).toBe(20);
|
|
169
|
+
});
|
|
170
|
+
});
|
package/lib/index.d.ts
CHANGED
|
@@ -2,14 +2,12 @@ declare class Semaphore {
|
|
|
2
2
|
private semaphoreInstances;
|
|
3
3
|
private maxConcurrent;
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
5
|
* @param {number} [maxConcurrent] The maximum number of concurrent locks.
|
|
7
6
|
*/
|
|
8
7
|
constructor(maxConcurrent?: number);
|
|
9
8
|
private hasSemaphoreInstance;
|
|
10
9
|
private getSemaphoreInstance;
|
|
11
10
|
/**
|
|
12
|
-
*
|
|
13
11
|
* @param {string | number} [key]- Optional, the semaphore key.
|
|
14
12
|
*/
|
|
15
13
|
private tidy;
|
|
@@ -22,12 +20,10 @@ declare class Semaphore {
|
|
|
22
20
|
*/
|
|
23
21
|
canAcquire(key?: string | number): boolean;
|
|
24
22
|
/**
|
|
25
|
-
*
|
|
26
23
|
* @param {string | number} [key]- Optional, the semaphore key.
|
|
27
24
|
*/
|
|
28
25
|
acquire(key?: string | number): Promise<void>;
|
|
29
26
|
/**
|
|
30
|
-
*
|
|
31
27
|
* @param {string | number} [key]- Optional, the semaphore key.
|
|
32
28
|
*/
|
|
33
29
|
release(key?: string | number): void;
|
|
@@ -38,13 +34,11 @@ declare class Semaphore {
|
|
|
38
34
|
*/
|
|
39
35
|
count(key?: string | number): number;
|
|
40
36
|
/**
|
|
41
|
-
*
|
|
42
37
|
* @param {string | number} [key]- Optional, the semaphore key.
|
|
43
38
|
* @returns {boolean} True if the semaphore and key has locks, false otherwise.
|
|
44
39
|
*/
|
|
45
40
|
hasTasks(key?: string | number): boolean;
|
|
46
41
|
/**
|
|
47
|
-
*
|
|
48
42
|
* @param {Function<T>} fn The function to execute.
|
|
49
43
|
* @param {string | number} [key]- Optional, the semaphore key.
|
|
50
44
|
* @returns {Promise<T>}
|
|
@@ -59,5 +53,6 @@ declare class Semaphore {
|
|
|
59
53
|
* @returns {Promise<T>}
|
|
60
54
|
*/
|
|
61
55
|
requestIfAvailable<T>(fn: Function, key?: string | number): Promise<T | null>;
|
|
56
|
+
wait(key?: string | number): Promise<void>;
|
|
62
57
|
}
|
|
63
58
|
export default Semaphore;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function e(e){var t=function(e){if("object"!=typeof e||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var n=t.call(e,"string");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==typeof t?t:t+""}var t=/*#__PURE__*/function(){function t(e){this.queue=void 0,this.maxConcurrent=void 0,this.count=void 0,this.queue=[],this.maxConcurrent=e,this.count=0}var n,r,i=t.prototype;return i.acquire=function(){var e=this;return this.canAcquire?(this.
|
|
1
|
+
function e(e){var t=function(e){if("object"!=typeof e||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var n=t.call(e,"string");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==typeof t?t:t+""}var t=/*#__PURE__*/function(){function t(e){this.queue=void 0,this.waitQueue=void 0,this.maxConcurrent=void 0,this.count=void 0,this.queue=[],this.waitQueue=[],this.maxConcurrent=e,this.count=0}var n,r,i=t.prototype;return i.incrementCount=function(){this.count++},i.decrementCount=function(){this.count--,0===this.count&&(this.waitQueue.forEach(function(e){return e()}),this.waitQueue=[])},i.acquire=function(){var e=this;return this.canAcquire?(this.incrementCount(),Promise.resolve()):new Promise(function(t){return e.queue.push(t)})},i.release=function(){var e=this.queue.shift();e?setTimeout(e,0):this.decrementCount()},i.wait=function(){var e=this;return new Promise(function(t){return e.waitQueue.push(t)})},n=t,(r=[{key:"canAcquire",get:function(){return this.count<this.maxConcurrent}}])&&function(t,n){for(var r=0;r<n.length;r++){var i=n[r];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,e(i.key),i)}}(n.prototype,r),Object.defineProperty(n,"prototype",{writable:!1}),n}(),n="_default";module.exports=/*#__PURE__*/function(){function e(e){void 0===e&&(e=1),this.semaphoreInstances=void 0,this.maxConcurrent=void 0,this.semaphoreInstances={},this.maxConcurrent=e}var r=e.prototype;return r.hasSemaphoreInstance=function(e){return void 0===e&&(e=n),Boolean(this.semaphoreInstances[e])},r.getSemaphoreInstance=function(e){return void 0===e&&(e=n),this.hasSemaphoreInstance(e)||(this.semaphoreInstances[e]=new t(this.maxConcurrent)),this.semaphoreInstances[e]},r.tidy=function(e){void 0===e&&(e=n),this.hasSemaphoreInstance(e)&&0===this.getSemaphoreInstance(e).count&&delete this.semaphoreInstances[e]},r.canAcquire=function(e){return void 0===e&&(e=n),this.getSemaphoreInstance(e).canAcquire},r.acquire=function(e){return void 0===e&&(e=n),this.getSemaphoreInstance(e).acquire()},r.release=function(e){void 0===e&&(e=n),this.getSemaphoreInstance(e).release(),this.tidy(e)},r.count=function(e){return void 0===e&&(e=n),this.hasSemaphoreInstance(e)?this.getSemaphoreInstance(e).count:0},r.hasTasks=function(e){return void 0===e&&(e=n),this.count(e)>0},r.request=function(e,t){void 0===t&&(t=n);try{var r=this;return Promise.resolve(function(n,i){try{var o=Promise.resolve(r.acquire(t)).then(function(){return Promise.resolve(e())})}catch(e){return i(!0,e)}return o&&o.then?o.then(i.bind(null,!1),i.bind(null,!0)):i(!1,o)}(0,function(e,n){if(r.release(t),e)throw n;return n}))}catch(e){return Promise.reject(e)}},r.requestIfAvailable=function(e,t){void 0===t&&(t=n);try{return this.canAcquire(t)?Promise.resolve(this.request(e,t)):Promise.resolve(null)}catch(e){return Promise.reject(e)}},r.wait=function(e){void 0===e&&(e=n);try{return this.hasTasks(e)?Promise.resolve(this.getSemaphoreInstance(e).wait()):Promise.resolve()}catch(e){return Promise.reject(e)}},e}();
|
|
2
2
|
//# sourceMappingURL=promise-semaphore.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promise-semaphore.cjs","sources":["../src/index.ts"],"sourcesContent":["class SemaphoreItem {\n private queue: Array<Function>;\n private maxConcurrent: number;\n /**\n * The number of locks.\n */\n public count: number;\n\n constructor(maxConcurrent: number) {\n this.queue = [];\n this.maxConcurrent = maxConcurrent;\n this.count = 0;\n }\n\n get canAcquire(): boolean {\n return this.count < this.maxConcurrent;\n }\n\n acquire(): Promise<void> {\n if (this.canAcquire) {\n this.
|
|
1
|
+
{"version":3,"file":"promise-semaphore.cjs","sources":["../src/index.ts"],"sourcesContent":["class SemaphoreItem {\n private queue: Array<Function>;\n private waitQueue: Array<Function>;\n private maxConcurrent: number;\n\n /**\n * The number of locks.\n */\n public count: number;\n\n constructor(maxConcurrent: number) {\n this.queue = [];\n this.waitQueue = [];\n this.maxConcurrent = maxConcurrent;\n this.count = 0;\n }\n\n get canAcquire(): boolean {\n return this.count < this.maxConcurrent;\n }\n\n private incrementCount() {\n this.count++;\n }\n\n private decrementCount() {\n this.count--;\n\n if (this.count === 0) {\n this.waitQueue.forEach((resolve) => resolve());\n this.waitQueue = [];\n }\n }\n\n acquire(): Promise<void> {\n if (this.canAcquire) {\n this.incrementCount();\n return Promise.resolve();\n } else {\n return new Promise((resolve) => this.queue.push(resolve));\n }\n }\n\n release(): void {\n const resolveFunc = this.queue.shift();\n\n if (resolveFunc) {\n // Give the micro task queue a small break instead of calling resolveFunc() directly\n setTimeout(resolveFunc, 0);\n } else {\n this.decrementCount();\n }\n }\n\n wait(): Promise<void> {\n return new Promise((resolve) => this.waitQueue.push(resolve));\n }\n}\n\nconst defaultKey = \"_default\";\n\nclass Semaphore {\n private semaphoreInstances: Record<string | number, SemaphoreItem>;\n private maxConcurrent: number;\n\n /**\n * @param {number} [maxConcurrent] The maximum number of concurrent locks.\n */\n constructor(maxConcurrent: number = 1) {\n this.semaphoreInstances = {};\n this.maxConcurrent = maxConcurrent;\n }\n\n private hasSemaphoreInstance(key: string | number = defaultKey) {\n return Boolean(this.semaphoreInstances[key]);\n }\n\n private getSemaphoreInstance(key: string | number = defaultKey) {\n if (!this.hasSemaphoreInstance(key)) {\n this.semaphoreInstances[key] = new SemaphoreItem(this.maxConcurrent);\n }\n return this.semaphoreInstances[key];\n }\n\n /**\n * @param {string | number} [key]- Optional, the semaphore key.\n */\n private tidy(key: string | number = defaultKey): void {\n if (\n this.hasSemaphoreInstance(key) &&\n this.getSemaphoreInstance(key).count === 0\n ) {\n delete this.semaphoreInstances[key];\n }\n }\n\n /**\n * A synchronous function to determine whether a lock can be acquired.\n *\n * @param {string | number} [key]- Optional, the semaphore key.\n * @returns {boolean} Returns true if the lock on `key` can be acquired, false\n * otherwise.\n */\n canAcquire(key: string | number = defaultKey): boolean {\n return this.getSemaphoreInstance(key).canAcquire;\n }\n\n /**\n * @param {string | number} [key]- Optional, the semaphore key.\n */\n acquire(key: string | number = defaultKey) {\n return this.getSemaphoreInstance(key).acquire();\n }\n\n /**\n * @param {string | number} [key]- Optional, the semaphore key.\n */\n release(key: string | number = defaultKey): void {\n this.getSemaphoreInstance(key).release();\n this.tidy(key);\n }\n\n /**\n * The number of active locks. Will always be less or equal to `max`.\n *\n * @param {string | number} [key]- Optional, the semaphore key.\n */\n count(key: string | number = defaultKey): number {\n if (this.hasSemaphoreInstance(key)) {\n return this.getSemaphoreInstance(key).count;\n } else {\n return 0;\n }\n }\n\n /**\n * @param {string | number} [key]- Optional, the semaphore key.\n * @returns {boolean} True if the semaphore and key has locks, false otherwise.\n */\n hasTasks(key: string | number = defaultKey): boolean {\n return this.count(key) > 0;\n }\n\n /**\n * @param {Function<T>} fn The function to execute.\n * @param {string | number} [key]- Optional, the semaphore key.\n * @returns {Promise<T>}\n */\n async request<T>(\n fn: Function,\n key: string | number = defaultKey,\n ): Promise<T> {\n try {\n await this.acquire(key);\n return await fn();\n } finally {\n this.release(key);\n }\n }\n\n /**\n * Asynchronously executes `fn` if a lock can be immediately acquired.\n * Otherwise, returns null.\n *\n * @param {Function<T>} fn The function to execute.\n * @param {string | number} [key]- Optional, the semaphore key.\n * @returns {Promise<T>}\n */\n async requestIfAvailable<T>(\n fn: Function,\n key: string | number = defaultKey,\n ): Promise<T | null> {\n if (this.canAcquire(key)) {\n return this.request(fn, key);\n } else {\n return null;\n }\n }\n\n async wait(key: string | number = defaultKey) {\n if (this.hasTasks(key)) {\n return this.getSemaphoreInstance(key).wait();\n } else {\n return Promise.resolve();\n }\n }\n}\n\nexport default Semaphore;\n"],"names":["SemaphoreItem","maxConcurrent","queue","waitQueue","count","this","_proto","prototype","incrementCount","decrementCount","forEach","resolve","acquire","_this","canAcquire","Promise","push","release","resolveFunc","shift","setTimeout","wait","_this2","key","get","defaultKey","Semaphore","semaphoreInstances","_proto2","hasSemaphoreInstance","Boolean","getSemaphoreInstance","tidy","hasTasks","request","fn","_this3","then","_finallyRethrows","_wasThrown","_result","e","reject","requestIfAvailable"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
class e{constructor(e){this.queue=void 0,this.maxConcurrent=void 0,this.count=void 0,this.queue=[],this.maxConcurrent=e,this.count=0}get canAcquire(){return this.count<this.maxConcurrent}acquire(){return this.canAcquire?(this.
|
|
1
|
+
class e{constructor(e){this.queue=void 0,this.waitQueue=void 0,this.maxConcurrent=void 0,this.count=void 0,this.queue=[],this.waitQueue=[],this.maxConcurrent=e,this.count=0}get canAcquire(){return this.count<this.maxConcurrent}incrementCount(){this.count++}decrementCount(){this.count--,0===this.count&&(this.waitQueue.forEach(e=>e()),this.waitQueue=[])}acquire(){return this.canAcquire?(this.incrementCount(),Promise.resolve()):new Promise(e=>this.queue.push(e))}release(){const e=this.queue.shift();e?setTimeout(e,0):this.decrementCount()}wait(){return new Promise(e=>this.waitQueue.push(e))}}const t="_default";class s{constructor(e=1){this.semaphoreInstances=void 0,this.maxConcurrent=void 0,this.semaphoreInstances={},this.maxConcurrent=e}hasSemaphoreInstance(e=t){return Boolean(this.semaphoreInstances[e])}getSemaphoreInstance(s=t){return this.hasSemaphoreInstance(s)||(this.semaphoreInstances[s]=new e(this.maxConcurrent)),this.semaphoreInstances[s]}tidy(e=t){this.hasSemaphoreInstance(e)&&0===this.getSemaphoreInstance(e).count&&delete this.semaphoreInstances[e]}canAcquire(e=t){return this.getSemaphoreInstance(e).canAcquire}acquire(e=t){return this.getSemaphoreInstance(e).acquire()}release(e=t){this.getSemaphoreInstance(e).release(),this.tidy(e)}count(e=t){return this.hasSemaphoreInstance(e)?this.getSemaphoreInstance(e).count:0}hasTasks(e=t){return this.count(e)>0}async request(e,s=t){try{return await this.acquire(s),await e()}finally{this.release(s)}}async requestIfAvailable(e,s=t){return this.canAcquire(s)?this.request(e,s):null}async wait(e=t){return this.hasTasks(e)?this.getSemaphoreInstance(e).wait():Promise.resolve()}}export{s as default};
|
|
2
2
|
//# sourceMappingURL=promise-semaphore.modern.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promise-semaphore.modern.js","sources":["../src/index.ts"],"sourcesContent":["class SemaphoreItem {\n private queue: Array<Function>;\n private maxConcurrent: number;\n /**\n * The number of locks.\n */\n public count: number;\n\n constructor(maxConcurrent: number) {\n this.queue = [];\n this.maxConcurrent = maxConcurrent;\n this.count = 0;\n }\n\n get canAcquire(): boolean {\n return this.count < this.maxConcurrent;\n }\n\n acquire(): Promise<void> {\n if (this.canAcquire) {\n this.
|
|
1
|
+
{"version":3,"file":"promise-semaphore.modern.js","sources":["../src/index.ts"],"sourcesContent":["class SemaphoreItem {\n private queue: Array<Function>;\n private waitQueue: Array<Function>;\n private maxConcurrent: number;\n\n /**\n * The number of locks.\n */\n public count: number;\n\n constructor(maxConcurrent: number) {\n this.queue = [];\n this.waitQueue = [];\n this.maxConcurrent = maxConcurrent;\n this.count = 0;\n }\n\n get canAcquire(): boolean {\n return this.count < this.maxConcurrent;\n }\n\n private incrementCount() {\n this.count++;\n }\n\n private decrementCount() {\n this.count--;\n\n if (this.count === 0) {\n this.waitQueue.forEach((resolve) => resolve());\n this.waitQueue = [];\n }\n }\n\n acquire(): Promise<void> {\n if (this.canAcquire) {\n this.incrementCount();\n return Promise.resolve();\n } else {\n return new Promise((resolve) => this.queue.push(resolve));\n }\n }\n\n release(): void {\n const resolveFunc = this.queue.shift();\n\n if (resolveFunc) {\n // Give the micro task queue a small break instead of calling resolveFunc() directly\n setTimeout(resolveFunc, 0);\n } else {\n this.decrementCount();\n }\n }\n\n wait(): Promise<void> {\n return new Promise((resolve) => this.waitQueue.push(resolve));\n }\n}\n\nconst defaultKey = \"_default\";\n\nclass Semaphore {\n private semaphoreInstances: Record<string | number, SemaphoreItem>;\n private maxConcurrent: number;\n\n /**\n * @param {number} [maxConcurrent] The maximum number of concurrent locks.\n */\n constructor(maxConcurrent: number = 1) {\n this.semaphoreInstances = {};\n this.maxConcurrent = maxConcurrent;\n }\n\n private hasSemaphoreInstance(key: string | number = defaultKey) {\n return Boolean(this.semaphoreInstances[key]);\n }\n\n private getSemaphoreInstance(key: string | number = defaultKey) {\n if (!this.hasSemaphoreInstance(key)) {\n this.semaphoreInstances[key] = new SemaphoreItem(this.maxConcurrent);\n }\n return this.semaphoreInstances[key];\n }\n\n /**\n * @param {string | number} [key]- Optional, the semaphore key.\n */\n private tidy(key: string | number = defaultKey): void {\n if (\n this.hasSemaphoreInstance(key) &&\n this.getSemaphoreInstance(key).count === 0\n ) {\n delete this.semaphoreInstances[key];\n }\n }\n\n /**\n * A synchronous function to determine whether a lock can be acquired.\n *\n * @param {string | number} [key]- Optional, the semaphore key.\n * @returns {boolean} Returns true if the lock on `key` can be acquired, false\n * otherwise.\n */\n canAcquire(key: string | number = defaultKey): boolean {\n return this.getSemaphoreInstance(key).canAcquire;\n }\n\n /**\n * @param {string | number} [key]- Optional, the semaphore key.\n */\n acquire(key: string | number = defaultKey) {\n return this.getSemaphoreInstance(key).acquire();\n }\n\n /**\n * @param {string | number} [key]- Optional, the semaphore key.\n */\n release(key: string | number = defaultKey): void {\n this.getSemaphoreInstance(key).release();\n this.tidy(key);\n }\n\n /**\n * The number of active locks. Will always be less or equal to `max`.\n *\n * @param {string | number} [key]- Optional, the semaphore key.\n */\n count(key: string | number = defaultKey): number {\n if (this.hasSemaphoreInstance(key)) {\n return this.getSemaphoreInstance(key).count;\n } else {\n return 0;\n }\n }\n\n /**\n * @param {string | number} [key]- Optional, the semaphore key.\n * @returns {boolean} True if the semaphore and key has locks, false otherwise.\n */\n hasTasks(key: string | number = defaultKey): boolean {\n return this.count(key) > 0;\n }\n\n /**\n * @param {Function<T>} fn The function to execute.\n * @param {string | number} [key]- Optional, the semaphore key.\n * @returns {Promise<T>}\n */\n async request<T>(\n fn: Function,\n key: string | number = defaultKey,\n ): Promise<T> {\n try {\n await this.acquire(key);\n return await fn();\n } finally {\n this.release(key);\n }\n }\n\n /**\n * Asynchronously executes `fn` if a lock can be immediately acquired.\n * Otherwise, returns null.\n *\n * @param {Function<T>} fn The function to execute.\n * @param {string | number} [key]- Optional, the semaphore key.\n * @returns {Promise<T>}\n */\n async requestIfAvailable<T>(\n fn: Function,\n key: string | number = defaultKey,\n ): Promise<T | null> {\n if (this.canAcquire(key)) {\n return this.request(fn, key);\n } else {\n return null;\n }\n }\n\n async wait(key: string | number = defaultKey) {\n if (this.hasTasks(key)) {\n return this.getSemaphoreInstance(key).wait();\n } else {\n return Promise.resolve();\n }\n }\n}\n\nexport default Semaphore;\n"],"names":["SemaphoreItem","constructor","maxConcurrent","this","queue","waitQueue","count","canAcquire","incrementCount","decrementCount","forEach","resolve","acquire","Promise","push","release","resolveFunc","shift","setTimeout","wait","defaultKey","Semaphore","semaphoreInstances","hasSemaphoreInstance","key","Boolean","getSemaphoreInstance","tidy","hasTasks","request","fn","requestIfAvailable"],"mappings":"AAAA,MAAMA,EAUJC,WAAAA,CAAYC,GAAqBC,KATzBC,WAAK,EAAAD,KACLE,eAAS,EAAAF,KACTD,mBAKDI,EAAAA,KAAAA,WAGL,EAAAH,KAAKC,MAAQ,GACbD,KAAKE,UAAY,GACjBF,KAAKD,cAAgBA,EACrBC,KAAKG,MAAQ,CACf,CAEA,cAAIC,GACF,YAAYD,MAAQH,KAAKD,aAC3B,CAEQM,cAAAA,GACNL,KAAKG,OACP,CAEQG,cAAAA,GACNN,KAAKG,QAEc,IAAfH,KAAKG,QACPH,KAAKE,UAAUK,QAASC,GAAYA,KACpCR,KAAKE,UAAY,GAErB,CAEAO,OAAAA,GACE,OAAIT,KAAKI,YACPJ,KAAKK,iBACEK,QAAQF,WAEJ,IAAAE,QAASF,GAAYR,KAAKC,MAAMU,KAAKH,GAEpD,CAEAI,OAAAA,GACE,MAAMC,EAAcb,KAAKC,MAAMa,QAE3BD,EAEFE,WAAWF,EAAa,GAExBb,KAAKM,gBAET,CAEAU,IAAAA,GACE,OAAW,IAAAN,QAASF,GAAYR,KAAKE,UAAUS,KAAKH,GACtD,EAGF,MAAMS,EAAa,WAEnB,MAAMC,EAOJpB,WAAAA,CAAYC,EAAwB,GAN5BoB,KAAAA,wBACApB,EAAAA,KAAAA,qBAMNC,KAAKmB,mBAAqB,GAC1BnB,KAAKD,cAAgBA,CACvB,CAEQqB,oBAAAA,CAAqBC,EAAuBJ,GAClD,OAAOK,QAAQtB,KAAKmB,mBAAmBE,GACzC,CAEQE,oBAAAA,CAAqBF,EAAuBJ,GAIlD,OAHKjB,KAAKoB,qBAAqBC,KAC7BrB,KAAKmB,mBAAmBE,GAAO,IAAIxB,EAAcG,KAAKD,gBAE7CC,KAACmB,mBAAmBE,EACjC,CAKQG,IAAAA,CAAKH,EAAuBJ,GAEhCjB,KAAKoB,qBAAqBC,IACe,IAAzCrB,KAAKuB,qBAAqBF,GAAKlB,cAEpBH,KAACmB,mBAAmBE,EAEnC,CASAjB,UAAAA,CAAWiB,EAAuBJ,GAChC,OAAWjB,KAACuB,qBAAqBF,GAAKjB,UACxC,CAKAK,OAAAA,CAAQY,EAAuBJ,GAC7B,OAAWjB,KAACuB,qBAAqBF,GAAKZ,SACxC,CAKAG,OAAAA,CAAQS,EAAuBJ,GAC7BjB,KAAKuB,qBAAqBF,GAAKT,UAC/BZ,KAAKwB,KAAKH,EACZ,CAOAlB,KAAAA,CAAMkB,EAAuBJ,GAC3B,OAAIjB,KAAKoB,qBAAqBC,GACrBrB,KAAKuB,qBAAqBF,GAAKlB,MAGvC,CACH,CAMAsB,QAAAA,CAASJ,EAAuBJ,GAC9B,OAAOjB,KAAKG,MAAMkB,GAAO,CAC3B,CAOA,aAAMK,CACJC,EACAN,EAAuBJ,GAEvB,IAEE,aADMjB,KAAKS,QAAQY,SACNM,GACd,CAAA,QACC3B,KAAKY,QAAQS,EACd,CACH,CAUA,wBAAMO,CACJD,EACAN,EAAuBJ,GAEvB,OAAIjB,KAAKI,WAAWiB,GACPrB,KAAC0B,QAAQC,EAAIN,GAEjB,IAEX,CAEA,UAAML,CAAKK,EAAuBJ,GAChC,OAAIjB,KAAKyB,SAASJ,GACLrB,KAACuB,qBAAqBF,GAAKL,OAE/BN,QAAQF,SAEnB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function e(e){var t=function(e){if("object"!=typeof e||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var n=t.call(e,"string");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==typeof t?t:t+""}var t=/*#__PURE__*/function(){function t(e){this.queue=void 0,this.maxConcurrent=void 0,this.count=void 0,this.queue=[],this.maxConcurrent=e,this.count=0}var n,r,i=t.prototype;return i.acquire=function(){var e=this;return this.canAcquire?(this.
|
|
1
|
+
function e(e){var t=function(e){if("object"!=typeof e||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var n=t.call(e,"string");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==typeof t?t:t+""}var t=/*#__PURE__*/function(){function t(e){this.queue=void 0,this.waitQueue=void 0,this.maxConcurrent=void 0,this.count=void 0,this.queue=[],this.waitQueue=[],this.maxConcurrent=e,this.count=0}var n,r,i=t.prototype;return i.incrementCount=function(){this.count++},i.decrementCount=function(){this.count--,0===this.count&&(this.waitQueue.forEach(function(e){return e()}),this.waitQueue=[])},i.acquire=function(){var e=this;return this.canAcquire?(this.incrementCount(),Promise.resolve()):new Promise(function(t){return e.queue.push(t)})},i.release=function(){var e=this.queue.shift();e?setTimeout(e,0):this.decrementCount()},i.wait=function(){var e=this;return new Promise(function(t){return e.waitQueue.push(t)})},n=t,(r=[{key:"canAcquire",get:function(){return this.count<this.maxConcurrent}}])&&function(t,n){for(var r=0;r<n.length;r++){var i=n[r];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,e(i.key),i)}}(n.prototype,r),Object.defineProperty(n,"prototype",{writable:!1}),n}(),n="_default",r=/*#__PURE__*/function(){function e(e){void 0===e&&(e=1),this.semaphoreInstances=void 0,this.maxConcurrent=void 0,this.semaphoreInstances={},this.maxConcurrent=e}var r=e.prototype;return r.hasSemaphoreInstance=function(e){return void 0===e&&(e=n),Boolean(this.semaphoreInstances[e])},r.getSemaphoreInstance=function(e){return void 0===e&&(e=n),this.hasSemaphoreInstance(e)||(this.semaphoreInstances[e]=new t(this.maxConcurrent)),this.semaphoreInstances[e]},r.tidy=function(e){void 0===e&&(e=n),this.hasSemaphoreInstance(e)&&0===this.getSemaphoreInstance(e).count&&delete this.semaphoreInstances[e]},r.canAcquire=function(e){return void 0===e&&(e=n),this.getSemaphoreInstance(e).canAcquire},r.acquire=function(e){return void 0===e&&(e=n),this.getSemaphoreInstance(e).acquire()},r.release=function(e){void 0===e&&(e=n),this.getSemaphoreInstance(e).release(),this.tidy(e)},r.count=function(e){return void 0===e&&(e=n),this.hasSemaphoreInstance(e)?this.getSemaphoreInstance(e).count:0},r.hasTasks=function(e){return void 0===e&&(e=n),this.count(e)>0},r.request=function(e,t){void 0===t&&(t=n);try{var r=this;return Promise.resolve(function(n,i){try{var o=Promise.resolve(r.acquire(t)).then(function(){return Promise.resolve(e())})}catch(e){return i(!0,e)}return o&&o.then?o.then(i.bind(null,!1),i.bind(null,!0)):i(!1,o)}(0,function(e,n){if(r.release(t),e)throw n;return n}))}catch(e){return Promise.reject(e)}},r.requestIfAvailable=function(e,t){void 0===t&&(t=n);try{return this.canAcquire(t)?Promise.resolve(this.request(e,t)):Promise.resolve(null)}catch(e){return Promise.reject(e)}},r.wait=function(e){void 0===e&&(e=n);try{return this.hasTasks(e)?Promise.resolve(this.getSemaphoreInstance(e).wait()):Promise.resolve()}catch(e){return Promise.reject(e)}},e}();export{r as default};
|
|
2
2
|
//# sourceMappingURL=promise-semaphore.module.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promise-semaphore.module.js","sources":["../src/index.ts"],"sourcesContent":["class SemaphoreItem {\n private queue: Array<Function>;\n private maxConcurrent: number;\n /**\n * The number of locks.\n */\n public count: number;\n\n constructor(maxConcurrent: number) {\n this.queue = [];\n this.maxConcurrent = maxConcurrent;\n this.count = 0;\n }\n\n get canAcquire(): boolean {\n return this.count < this.maxConcurrent;\n }\n\n acquire(): Promise<void> {\n if (this.canAcquire) {\n this.
|
|
1
|
+
{"version":3,"file":"promise-semaphore.module.js","sources":["../src/index.ts"],"sourcesContent":["class SemaphoreItem {\n private queue: Array<Function>;\n private waitQueue: Array<Function>;\n private maxConcurrent: number;\n\n /**\n * The number of locks.\n */\n public count: number;\n\n constructor(maxConcurrent: number) {\n this.queue = [];\n this.waitQueue = [];\n this.maxConcurrent = maxConcurrent;\n this.count = 0;\n }\n\n get canAcquire(): boolean {\n return this.count < this.maxConcurrent;\n }\n\n private incrementCount() {\n this.count++;\n }\n\n private decrementCount() {\n this.count--;\n\n if (this.count === 0) {\n this.waitQueue.forEach((resolve) => resolve());\n this.waitQueue = [];\n }\n }\n\n acquire(): Promise<void> {\n if (this.canAcquire) {\n this.incrementCount();\n return Promise.resolve();\n } else {\n return new Promise((resolve) => this.queue.push(resolve));\n }\n }\n\n release(): void {\n const resolveFunc = this.queue.shift();\n\n if (resolveFunc) {\n // Give the micro task queue a small break instead of calling resolveFunc() directly\n setTimeout(resolveFunc, 0);\n } else {\n this.decrementCount();\n }\n }\n\n wait(): Promise<void> {\n return new Promise((resolve) => this.waitQueue.push(resolve));\n }\n}\n\nconst defaultKey = \"_default\";\n\nclass Semaphore {\n private semaphoreInstances: Record<string | number, SemaphoreItem>;\n private maxConcurrent: number;\n\n /**\n * @param {number} [maxConcurrent] The maximum number of concurrent locks.\n */\n constructor(maxConcurrent: number = 1) {\n this.semaphoreInstances = {};\n this.maxConcurrent = maxConcurrent;\n }\n\n private hasSemaphoreInstance(key: string | number = defaultKey) {\n return Boolean(this.semaphoreInstances[key]);\n }\n\n private getSemaphoreInstance(key: string | number = defaultKey) {\n if (!this.hasSemaphoreInstance(key)) {\n this.semaphoreInstances[key] = new SemaphoreItem(this.maxConcurrent);\n }\n return this.semaphoreInstances[key];\n }\n\n /**\n * @param {string | number} [key]- Optional, the semaphore key.\n */\n private tidy(key: string | number = defaultKey): void {\n if (\n this.hasSemaphoreInstance(key) &&\n this.getSemaphoreInstance(key).count === 0\n ) {\n delete this.semaphoreInstances[key];\n }\n }\n\n /**\n * A synchronous function to determine whether a lock can be acquired.\n *\n * @param {string | number} [key]- Optional, the semaphore key.\n * @returns {boolean} Returns true if the lock on `key` can be acquired, false\n * otherwise.\n */\n canAcquire(key: string | number = defaultKey): boolean {\n return this.getSemaphoreInstance(key).canAcquire;\n }\n\n /**\n * @param {string | number} [key]- Optional, the semaphore key.\n */\n acquire(key: string | number = defaultKey) {\n return this.getSemaphoreInstance(key).acquire();\n }\n\n /**\n * @param {string | number} [key]- Optional, the semaphore key.\n */\n release(key: string | number = defaultKey): void {\n this.getSemaphoreInstance(key).release();\n this.tidy(key);\n }\n\n /**\n * The number of active locks. Will always be less or equal to `max`.\n *\n * @param {string | number} [key]- Optional, the semaphore key.\n */\n count(key: string | number = defaultKey): number {\n if (this.hasSemaphoreInstance(key)) {\n return this.getSemaphoreInstance(key).count;\n } else {\n return 0;\n }\n }\n\n /**\n * @param {string | number} [key]- Optional, the semaphore key.\n * @returns {boolean} True if the semaphore and key has locks, false otherwise.\n */\n hasTasks(key: string | number = defaultKey): boolean {\n return this.count(key) > 0;\n }\n\n /**\n * @param {Function<T>} fn The function to execute.\n * @param {string | number} [key]- Optional, the semaphore key.\n * @returns {Promise<T>}\n */\n async request<T>(\n fn: Function,\n key: string | number = defaultKey,\n ): Promise<T> {\n try {\n await this.acquire(key);\n return await fn();\n } finally {\n this.release(key);\n }\n }\n\n /**\n * Asynchronously executes `fn` if a lock can be immediately acquired.\n * Otherwise, returns null.\n *\n * @param {Function<T>} fn The function to execute.\n * @param {string | number} [key]- Optional, the semaphore key.\n * @returns {Promise<T>}\n */\n async requestIfAvailable<T>(\n fn: Function,\n key: string | number = defaultKey,\n ): Promise<T | null> {\n if (this.canAcquire(key)) {\n return this.request(fn, key);\n } else {\n return null;\n }\n }\n\n async wait(key: string | number = defaultKey) {\n if (this.hasTasks(key)) {\n return this.getSemaphoreInstance(key).wait();\n } else {\n return Promise.resolve();\n }\n }\n}\n\nexport default Semaphore;\n"],"names":["SemaphoreItem","maxConcurrent","queue","waitQueue","count","this","_proto","prototype","incrementCount","decrementCount","forEach","resolve","acquire","_this","canAcquire","Promise","push","release","resolveFunc","shift","setTimeout","wait","_this2","key","get","defaultKey","Semaphore","semaphoreInstances","_proto2","hasSemaphoreInstance","Boolean","getSemaphoreInstance","tidy","hasTasks","request","fn","_this3","then","_finallyRethrows","_wasThrown","_result","e","reject","requestIfAvailable"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chriscdn/promise-semaphore",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.11",
|
|
4
4
|
"description": "Limit or throttle the simultaneous execution of asynchronous code in separate iterations of the event loop.",
|
|
5
5
|
"repository": "https://github.com/chriscdn/promise-semaphore",
|
|
6
6
|
"author": "Christopher Meyer <chris@schwiiz.org>",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"microbundle": "^0.15.1",
|
|
26
|
-
"vitest": "^3.
|
|
26
|
+
"vitest": "^3.1.2"
|
|
27
27
|
},
|
|
28
28
|
"keywords": [
|
|
29
29
|
"promise",
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
class SemaphoreItem {
|
|
2
2
|
private queue: Array<Function>;
|
|
3
|
+
private waitQueue: Array<Function>;
|
|
3
4
|
private maxConcurrent: number;
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
7
|
* The number of locks.
|
|
6
8
|
*/
|
|
@@ -8,6 +10,7 @@ class SemaphoreItem {
|
|
|
8
10
|
|
|
9
11
|
constructor(maxConcurrent: number) {
|
|
10
12
|
this.queue = [];
|
|
13
|
+
this.waitQueue = [];
|
|
11
14
|
this.maxConcurrent = maxConcurrent;
|
|
12
15
|
this.count = 0;
|
|
13
16
|
}
|
|
@@ -16,9 +19,22 @@ class SemaphoreItem {
|
|
|
16
19
|
return this.count < this.maxConcurrent;
|
|
17
20
|
}
|
|
18
21
|
|
|
22
|
+
private incrementCount() {
|
|
23
|
+
this.count++;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private decrementCount() {
|
|
27
|
+
this.count--;
|
|
28
|
+
|
|
29
|
+
if (this.count === 0) {
|
|
30
|
+
this.waitQueue.forEach((resolve) => resolve());
|
|
31
|
+
this.waitQueue = [];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
19
35
|
acquire(): Promise<void> {
|
|
20
36
|
if (this.canAcquire) {
|
|
21
|
-
this.
|
|
37
|
+
this.incrementCount();
|
|
22
38
|
return Promise.resolve();
|
|
23
39
|
} else {
|
|
24
40
|
return new Promise((resolve) => this.queue.push(resolve));
|
|
@@ -31,11 +47,14 @@ class SemaphoreItem {
|
|
|
31
47
|
if (resolveFunc) {
|
|
32
48
|
// Give the micro task queue a small break instead of calling resolveFunc() directly
|
|
33
49
|
setTimeout(resolveFunc, 0);
|
|
34
|
-
// resolveFunc()
|
|
35
50
|
} else {
|
|
36
|
-
this.
|
|
51
|
+
this.decrementCount();
|
|
37
52
|
}
|
|
38
53
|
}
|
|
54
|
+
|
|
55
|
+
wait(): Promise<void> {
|
|
56
|
+
return new Promise((resolve) => this.waitQueue.push(resolve));
|
|
57
|
+
}
|
|
39
58
|
}
|
|
40
59
|
|
|
41
60
|
const defaultKey = "_default";
|
|
@@ -45,7 +64,6 @@ class Semaphore {
|
|
|
45
64
|
private maxConcurrent: number;
|
|
46
65
|
|
|
47
66
|
/**
|
|
48
|
-
*
|
|
49
67
|
* @param {number} [maxConcurrent] The maximum number of concurrent locks.
|
|
50
68
|
*/
|
|
51
69
|
constructor(maxConcurrent: number = 1) {
|
|
@@ -65,7 +83,6 @@ class Semaphore {
|
|
|
65
83
|
}
|
|
66
84
|
|
|
67
85
|
/**
|
|
68
|
-
*
|
|
69
86
|
* @param {string | number} [key]- Optional, the semaphore key.
|
|
70
87
|
*/
|
|
71
88
|
private tidy(key: string | number = defaultKey): void {
|
|
@@ -89,7 +106,6 @@ class Semaphore {
|
|
|
89
106
|
}
|
|
90
107
|
|
|
91
108
|
/**
|
|
92
|
-
*
|
|
93
109
|
* @param {string | number} [key]- Optional, the semaphore key.
|
|
94
110
|
*/
|
|
95
111
|
acquire(key: string | number = defaultKey) {
|
|
@@ -97,7 +113,6 @@ class Semaphore {
|
|
|
97
113
|
}
|
|
98
114
|
|
|
99
115
|
/**
|
|
100
|
-
*
|
|
101
116
|
* @param {string | number} [key]- Optional, the semaphore key.
|
|
102
117
|
*/
|
|
103
118
|
release(key: string | number = defaultKey): void {
|
|
@@ -119,7 +134,6 @@ class Semaphore {
|
|
|
119
134
|
}
|
|
120
135
|
|
|
121
136
|
/**
|
|
122
|
-
*
|
|
123
137
|
* @param {string | number} [key]- Optional, the semaphore key.
|
|
124
138
|
* @returns {boolean} True if the semaphore and key has locks, false otherwise.
|
|
125
139
|
*/
|
|
@@ -128,14 +142,13 @@ class Semaphore {
|
|
|
128
142
|
}
|
|
129
143
|
|
|
130
144
|
/**
|
|
131
|
-
*
|
|
132
145
|
* @param {Function<T>} fn The function to execute.
|
|
133
146
|
* @param {string | number} [key]- Optional, the semaphore key.
|
|
134
147
|
* @returns {Promise<T>}
|
|
135
148
|
*/
|
|
136
149
|
async request<T>(
|
|
137
150
|
fn: Function,
|
|
138
|
-
key: string | number = defaultKey
|
|
151
|
+
key: string | number = defaultKey,
|
|
139
152
|
): Promise<T> {
|
|
140
153
|
try {
|
|
141
154
|
await this.acquire(key);
|
|
@@ -155,7 +168,7 @@ class Semaphore {
|
|
|
155
168
|
*/
|
|
156
169
|
async requestIfAvailable<T>(
|
|
157
170
|
fn: Function,
|
|
158
|
-
key: string | number = defaultKey
|
|
171
|
+
key: string | number = defaultKey,
|
|
159
172
|
): Promise<T | null> {
|
|
160
173
|
if (this.canAcquire(key)) {
|
|
161
174
|
return this.request(fn, key);
|
|
@@ -163,6 +176,14 @@ class Semaphore {
|
|
|
163
176
|
return null;
|
|
164
177
|
}
|
|
165
178
|
}
|
|
179
|
+
|
|
180
|
+
async wait(key: string | number = defaultKey) {
|
|
181
|
+
if (this.hasTasks(key)) {
|
|
182
|
+
return this.getSemaphoreInstance(key).wait();
|
|
183
|
+
} else {
|
|
184
|
+
return Promise.resolve();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
166
187
|
}
|
|
167
188
|
|
|
168
189
|
export default Semaphore;
|