@chriscdn/promise-semaphore 2.0.1 → 2.0.3
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/__tests__/semaphore.test.ts +76 -76
- package/lib/index.d.ts +63 -64
- package/lib/promise-semaphore.cjs +2 -0
- package/lib/promise-semaphore.cjs.map +1 -0
- package/lib/promise-semaphore.modern.js +2 -0
- package/lib/promise-semaphore.modern.js.map +1 -0
- package/lib/promise-semaphore.module.js +2 -0
- package/lib/promise-semaphore.module.js.map +1 -0
- package/lib/promise-semaphore.umd.js +3 -0
- package/lib/promise-semaphore.umd.js.map +1 -0
- package/package.json +14 -15
- package/src/index.ts +35 -35
- package/.prettierrc +0 -4
- package/lib/index.cjs.js +0 -141
- package/lib/index.es.js +0 -139
- package/rollup.config.mjs +0 -40
- package/tsconfig.json +0 -6
|
@@ -1,143 +1,143 @@
|
|
|
1
|
-
import Semaphore from
|
|
1
|
+
import Semaphore from "../src/index";
|
|
2
2
|
|
|
3
|
-
const pause = async (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
3
|
+
const pause = async (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
4
4
|
|
|
5
|
-
test(
|
|
6
|
-
const semaphore = new Semaphore()
|
|
7
|
-
expect(semaphore.canAcquire()).toBe(true)
|
|
8
|
-
await semaphore.acquire()
|
|
9
|
-
expect(semaphore.canAcquire()).toBe(false)
|
|
10
|
-
expect(semaphore.hasTasks()).toBe(true)
|
|
11
|
-
expect(semaphore.count()).toBe(1)
|
|
12
|
-
semaphore.release()
|
|
13
|
-
expect(semaphore.canAcquire()).toBe(true)
|
|
14
|
-
expect(semaphore.count()).toBe(0)
|
|
15
|
-
})
|
|
5
|
+
test("Acquire & Release Basic", async () => {
|
|
6
|
+
const semaphore = new Semaphore();
|
|
7
|
+
expect(semaphore.canAcquire()).toBe(true);
|
|
8
|
+
await semaphore.acquire();
|
|
9
|
+
expect(semaphore.canAcquire()).toBe(false);
|
|
10
|
+
expect(semaphore.hasTasks()).toBe(true);
|
|
11
|
+
expect(semaphore.count()).toBe(1);
|
|
12
|
+
semaphore.release();
|
|
13
|
+
expect(semaphore.canAcquire()).toBe(true);
|
|
14
|
+
expect(semaphore.count()).toBe(0);
|
|
15
|
+
});
|
|
16
16
|
|
|
17
|
-
test(
|
|
18
|
-
const semaphore = new Semaphore()
|
|
17
|
+
test("Semaphore 1", async () => {
|
|
18
|
+
const semaphore = new Semaphore();
|
|
19
19
|
|
|
20
20
|
semaphore
|
|
21
21
|
.acquire()
|
|
22
22
|
.then(async () => await pause(1000))
|
|
23
|
-
.finally(() => semaphore.release())
|
|
23
|
+
.finally(() => semaphore.release());
|
|
24
24
|
|
|
25
|
-
expect(semaphore.canAcquire()).toBe(false)
|
|
25
|
+
expect(semaphore.canAcquire()).toBe(false);
|
|
26
26
|
|
|
27
|
-
await pause(600)
|
|
27
|
+
await pause(600);
|
|
28
28
|
|
|
29
|
-
expect(semaphore.canAcquire()).toBe(false)
|
|
29
|
+
expect(semaphore.canAcquire()).toBe(false);
|
|
30
30
|
|
|
31
|
-
await pause(600)
|
|
31
|
+
await pause(600);
|
|
32
32
|
|
|
33
|
-
expect(semaphore.canAcquire()).toBe(true)
|
|
34
|
-
})
|
|
33
|
+
expect(semaphore.canAcquire()).toBe(true);
|
|
34
|
+
});
|
|
35
35
|
|
|
36
|
-
test(
|
|
37
|
-
const semaphore = new Semaphore()
|
|
36
|
+
test("Semaphore 2", async () => {
|
|
37
|
+
const semaphore = new Semaphore();
|
|
38
38
|
|
|
39
|
-
let tester = 0
|
|
39
|
+
let tester = 0;
|
|
40
40
|
|
|
41
41
|
semaphore
|
|
42
42
|
.acquire()
|
|
43
43
|
.then(() => pause(1000))
|
|
44
44
|
.then(() => (tester = 10))
|
|
45
|
-
.finally(() => semaphore.release())
|
|
45
|
+
.finally(() => semaphore.release());
|
|
46
46
|
|
|
47
47
|
// tests acquire waits for previous to complete
|
|
48
48
|
await semaphore
|
|
49
49
|
.acquire()
|
|
50
50
|
.then(() => expect(tester).toBe(10))
|
|
51
|
-
.finally(() => semaphore.release())
|
|
52
|
-
})
|
|
51
|
+
.finally(() => semaphore.release());
|
|
52
|
+
});
|
|
53
53
|
|
|
54
|
-
test(
|
|
55
|
-
const semaphore = new Semaphore(2)
|
|
54
|
+
test("Semaphore 3", async () => {
|
|
55
|
+
const semaphore = new Semaphore(2);
|
|
56
56
|
|
|
57
|
-
let tester = 0
|
|
57
|
+
let tester = 0;
|
|
58
58
|
|
|
59
59
|
semaphore
|
|
60
60
|
.acquire()
|
|
61
61
|
.then(() => pause(1000))
|
|
62
62
|
.then(() => (tester = 20))
|
|
63
|
-
.finally(() => semaphore.release())
|
|
63
|
+
.finally(() => semaphore.release());
|
|
64
64
|
|
|
65
65
|
semaphore
|
|
66
66
|
.acquire()
|
|
67
67
|
.then(() => pause(500))
|
|
68
68
|
.then(() => (tester = 10))
|
|
69
|
-
.finally(() => semaphore.release())
|
|
69
|
+
.finally(() => semaphore.release());
|
|
70
70
|
|
|
71
|
-
expect(semaphore.count()).toBe(2)
|
|
72
|
-
expect(semaphore.hasTasks()).toBe(true)
|
|
71
|
+
expect(semaphore.count()).toBe(2);
|
|
72
|
+
expect(semaphore.hasTasks()).toBe(true);
|
|
73
73
|
|
|
74
74
|
// expect 10 since this next block will run before the first has completed
|
|
75
75
|
await semaphore
|
|
76
76
|
.acquire()
|
|
77
77
|
.then(() => expect(tester).toBe(10))
|
|
78
|
-
.finally(() => semaphore.release())
|
|
78
|
+
.finally(() => semaphore.release());
|
|
79
79
|
|
|
80
|
-
expect(semaphore.count()).toBe(1)
|
|
81
|
-
expect(semaphore.hasTasks()).toBe(true)
|
|
82
|
-
expect(semaphore.canAcquire()).toBe(true)
|
|
83
|
-
})
|
|
80
|
+
expect(semaphore.count()).toBe(1);
|
|
81
|
+
expect(semaphore.hasTasks()).toBe(true);
|
|
82
|
+
expect(semaphore.canAcquire()).toBe(true);
|
|
83
|
+
});
|
|
84
84
|
|
|
85
|
-
test(
|
|
86
|
-
const semaphore = new Semaphore()
|
|
85
|
+
test("Request 1", async () => {
|
|
86
|
+
const semaphore = new Semaphore();
|
|
87
87
|
|
|
88
|
-
let tester = 0
|
|
88
|
+
let tester = 0;
|
|
89
89
|
|
|
90
90
|
semaphore.request(async () => {
|
|
91
|
-
await pause(1000)
|
|
92
|
-
tester = 20
|
|
93
|
-
})
|
|
91
|
+
await pause(1000);
|
|
92
|
+
tester = 20;
|
|
93
|
+
});
|
|
94
94
|
|
|
95
95
|
semaphore.request(async () => {
|
|
96
|
-
await pause(500)
|
|
97
|
-
tester = 10
|
|
98
|
-
})
|
|
96
|
+
await pause(500);
|
|
97
|
+
tester = 10;
|
|
98
|
+
});
|
|
99
99
|
|
|
100
100
|
await semaphore.request(async () => {
|
|
101
|
-
expect(tester).toBe(10)
|
|
102
|
-
})
|
|
103
|
-
})
|
|
101
|
+
expect(tester).toBe(10);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
104
|
|
|
105
|
-
test(
|
|
106
|
-
const semaphore = new Semaphore(2)
|
|
105
|
+
test("Request 2", async () => {
|
|
106
|
+
const semaphore = new Semaphore(2);
|
|
107
107
|
|
|
108
|
-
let tester = 0
|
|
108
|
+
let tester = 0;
|
|
109
109
|
|
|
110
110
|
semaphore.request(async () => {
|
|
111
|
-
await pause(1000)
|
|
112
|
-
tester = 20
|
|
113
|
-
})
|
|
111
|
+
await pause(1000);
|
|
112
|
+
tester = 20;
|
|
113
|
+
});
|
|
114
114
|
|
|
115
115
|
semaphore.request(async () => {
|
|
116
|
-
await pause(500)
|
|
117
|
-
tester = 10
|
|
118
|
-
})
|
|
116
|
+
await pause(500);
|
|
117
|
+
tester = 10;
|
|
118
|
+
});
|
|
119
119
|
|
|
120
120
|
await semaphore.request(async () => {
|
|
121
|
-
expect(tester).toBe(10)
|
|
122
|
-
})
|
|
123
|
-
})
|
|
121
|
+
expect(tester).toBe(10);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
124
|
|
|
125
|
-
test(
|
|
126
|
-
const semaphore = new Semaphore(3)
|
|
125
|
+
test("Request 3", async () => {
|
|
126
|
+
const semaphore = new Semaphore(3);
|
|
127
127
|
|
|
128
|
-
let tester = 0
|
|
128
|
+
let tester = 0;
|
|
129
129
|
|
|
130
130
|
semaphore.request(async () => {
|
|
131
|
-
await pause(1000)
|
|
132
|
-
tester = 20
|
|
133
|
-
})
|
|
131
|
+
await pause(1000);
|
|
132
|
+
tester = 20;
|
|
133
|
+
});
|
|
134
134
|
|
|
135
135
|
semaphore.request(async () => {
|
|
136
|
-
await pause(500)
|
|
137
|
-
tester = 10
|
|
138
|
-
})
|
|
136
|
+
await pause(500);
|
|
137
|
+
tester = 10;
|
|
138
|
+
});
|
|
139
139
|
|
|
140
140
|
await semaphore.request(async () => {
|
|
141
|
-
expect(tester).toBe(0)
|
|
142
|
-
})
|
|
143
|
-
})
|
|
141
|
+
expect(tester).toBe(0);
|
|
142
|
+
});
|
|
143
|
+
});
|
package/lib/index.d.ts
CHANGED
|
@@ -1,64 +1,63 @@
|
|
|
1
|
-
declare class Semaphore {
|
|
2
|
-
private semaphoreInstances;
|
|
3
|
-
private maxConcurrent;
|
|
4
|
-
/**
|
|
5
|
-
*
|
|
6
|
-
* @param {number} [maxConcurrent] The maximum number of concurrent locks.
|
|
7
|
-
*/
|
|
8
|
-
constructor(maxConcurrent?: number);
|
|
9
|
-
private hasSemaphoreInstance;
|
|
10
|
-
private getSemaphoreInstance;
|
|
11
|
-
/**
|
|
12
|
-
*
|
|
13
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
14
|
-
*/
|
|
15
|
-
private tidy;
|
|
16
|
-
/**
|
|
17
|
-
* A synchronous function to determine whether a lock can be acquired.
|
|
18
|
-
*
|
|
19
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
20
|
-
* @returns {boolean} Returns true if the lock on `key` can be acquired, false
|
|
21
|
-
* otherwise.
|
|
22
|
-
*/
|
|
23
|
-
canAcquire(key?: string | number): boolean;
|
|
24
|
-
/**
|
|
25
|
-
*
|
|
26
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
27
|
-
*/
|
|
28
|
-
acquire(key?: string | number): Promise<void>;
|
|
29
|
-
/**
|
|
30
|
-
*
|
|
31
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
32
|
-
*/
|
|
33
|
-
release(key?: string | number): void;
|
|
34
|
-
/**
|
|
35
|
-
* The number of active locks. Will always be less or equal to `max`.
|
|
36
|
-
*
|
|
37
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
38
|
-
*/
|
|
39
|
-
count(key?: string | number): number;
|
|
40
|
-
/**
|
|
41
|
-
*
|
|
42
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
43
|
-
* @returns {boolean} True if the semaphore and key has locks, false otherwise.
|
|
44
|
-
*/
|
|
45
|
-
hasTasks(key?: string | number): boolean;
|
|
46
|
-
/**
|
|
47
|
-
*
|
|
48
|
-
* @param {Function<T>} fn The function to execute.
|
|
49
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
50
|
-
* @returns {Promise<T>}
|
|
51
|
-
*/
|
|
52
|
-
request<T>(fn: Function, key?: string | number): Promise<T>;
|
|
53
|
-
/**
|
|
54
|
-
* Asynchronously executes `fn` if a lock can be immediately acquired.
|
|
55
|
-
* Otherwise, returns null.
|
|
56
|
-
*
|
|
57
|
-
* @param {Function<T>} fn The function to execute.
|
|
58
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
59
|
-
* @returns {Promise<T>}
|
|
60
|
-
*/
|
|
61
|
-
requestIfAvailable<T>(fn: Function, key?: string | number): Promise<T | null>;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export { Semaphore as default };
|
|
1
|
+
declare class Semaphore {
|
|
2
|
+
private semaphoreInstances;
|
|
3
|
+
private maxConcurrent;
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {number} [maxConcurrent] The maximum number of concurrent locks.
|
|
7
|
+
*/
|
|
8
|
+
constructor(maxConcurrent?: number);
|
|
9
|
+
private hasSemaphoreInstance;
|
|
10
|
+
private getSemaphoreInstance;
|
|
11
|
+
/**
|
|
12
|
+
*
|
|
13
|
+
* @param {string | number} [key]- Optional, the semaphore key.
|
|
14
|
+
*/
|
|
15
|
+
private tidy;
|
|
16
|
+
/**
|
|
17
|
+
* A synchronous function to determine whether a lock can be acquired.
|
|
18
|
+
*
|
|
19
|
+
* @param {string | number} [key]- Optional, the semaphore key.
|
|
20
|
+
* @returns {boolean} Returns true if the lock on `key` can be acquired, false
|
|
21
|
+
* otherwise.
|
|
22
|
+
*/
|
|
23
|
+
canAcquire(key?: string | number): boolean;
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
* @param {string | number} [key]- Optional, the semaphore key.
|
|
27
|
+
*/
|
|
28
|
+
acquire(key?: string | number): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
* @param {string | number} [key]- Optional, the semaphore key.
|
|
32
|
+
*/
|
|
33
|
+
release(key?: string | number): void;
|
|
34
|
+
/**
|
|
35
|
+
* The number of active locks. Will always be less or equal to `max`.
|
|
36
|
+
*
|
|
37
|
+
* @param {string | number} [key]- Optional, the semaphore key.
|
|
38
|
+
*/
|
|
39
|
+
count(key?: string | number): number;
|
|
40
|
+
/**
|
|
41
|
+
*
|
|
42
|
+
* @param {string | number} [key]- Optional, the semaphore key.
|
|
43
|
+
* @returns {boolean} True if the semaphore and key has locks, false otherwise.
|
|
44
|
+
*/
|
|
45
|
+
hasTasks(key?: string | number): boolean;
|
|
46
|
+
/**
|
|
47
|
+
*
|
|
48
|
+
* @param {Function<T>} fn The function to execute.
|
|
49
|
+
* @param {string | number} [key]- Optional, the semaphore key.
|
|
50
|
+
* @returns {Promise<T>}
|
|
51
|
+
*/
|
|
52
|
+
request<T>(fn: Function, key?: string | number): Promise<T>;
|
|
53
|
+
/**
|
|
54
|
+
* Asynchronously executes `fn` if a lock can be immediately acquired.
|
|
55
|
+
* Otherwise, returns null.
|
|
56
|
+
*
|
|
57
|
+
* @param {Function<T>} fn The function to execute.
|
|
58
|
+
* @param {string | number} [key]- Optional, the semaphore key.
|
|
59
|
+
* @returns {Promise<T>}
|
|
60
|
+
*/
|
|
61
|
+
requestIfAvailable<T>(fn: Function, key?: string | number): Promise<T | null>;
|
|
62
|
+
}
|
|
63
|
+
export default Semaphore;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=/*#__PURE__*/function(){function e(e){this.queue=void 0,this.maxConcurrent=void 0,this.count=void 0,this.queue=[],this.maxConcurrent=e,this.count=0}var t,n,r=e.prototype;return r.acquire=function(){var e=this;return this.canAcquire?(this.count++,Promise.resolve()):new Promise(function(t){return e.queue.push(t)})},r.release=function(){var e=this.queue.shift();e?setTimeout(e,0):this.count--},t=e,(n=[{key:"canAcquire",get:function(){return this.count<this.maxConcurrent}}])&&function(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,"symbol"==typeof(i=function(e,t){if("object"!=typeof e||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,"string");if("object"!=typeof r)return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(r.key))?i:String(i),r)}var i}(t.prototype,n),Object.defineProperty(t,"prototype",{writable:!1}),e}(),t="_default";module.exports=/*#__PURE__*/function(){function n(e){void 0===e&&(e=1),this.semaphoreInstances=void 0,this.maxConcurrent=void 0,this.semaphoreInstances={},this.maxConcurrent=e}var r=n.prototype;return r.hasSemaphoreInstance=function(e){return void 0===e&&(e=t),Boolean(this.semaphoreInstances[e])},r.getSemaphoreInstance=function(n){return void 0===n&&(n=t),this.hasSemaphoreInstance(n)||(this.semaphoreInstances[n]=new e(this.maxConcurrent)),this.semaphoreInstances[n]},r.tidy=function(e){void 0===e&&(e=t),this.hasSemaphoreInstance(e)&&0==this.getSemaphoreInstance(e).count&&delete this.semaphoreInstances[e]},r.canAcquire=function(e){return void 0===e&&(e=t),this.getSemaphoreInstance(e).canAcquire},r.acquire=function(e){return void 0===e&&(e=t),this.getSemaphoreInstance(e).acquire()},r.release=function(e){void 0===e&&(e=t),this.getSemaphoreInstance(e).release(),this.tidy(e)},r.count=function(e){return void 0===e&&(e=t),this.hasSemaphoreInstance(e)?this.getSemaphoreInstance(e).count:0},r.hasTasks=function(e){return void 0===e&&(e=t),this.count(e)>0},r.request=function(e,n){void 0===n&&(n=t);try{var r=this;return Promise.resolve(function(t,i){try{var o=Promise.resolve(r.acquire(n)).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,t){if(r.release(n),e)throw t;return t}))}catch(e){return Promise.reject(e)}},r.requestIfAvailable=function(e,n){void 0===n&&(n=t);try{return this.canAcquire(n)?Promise.resolve(this.request(e,n)):Promise.resolve(null)}catch(e){return Promise.reject(e)}},n}();
|
|
2
|
+
//# sourceMappingURL=promise-semaphore.cjs.map
|
|
@@ -0,0 +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.count++;\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 // resolveFunc()\n } else {\n this.count--;\n }\n }\n}\n\nconst defaultKey = \"_default\";\n\nclass Semaphore {\n private semaphoreInstances: Record<string | number, SemaphoreItem>;\n private maxConcurrent: number;\n\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 *\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 *\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 *\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 *\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 *\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\nexport default Semaphore;\n"],"names":["SemaphoreItem","maxConcurrent","this","queue","count","_proto","prototype","acquire","_this","canAcquire","Promise","resolve","push","release","resolveFunc","shift","setTimeout","key","get","defaultKey","Semaphore","semaphoreInstances","_proto2","hasSemaphoreInstance","Boolean","getSemaphoreInstance","tidy","hasTasks","request","fn","_this2","then","_finallyRethrows","_wasThrown","_result","e","reject","requestIfAvailable"],"mappings":"IAAMA,0BAQJ,SAAAA,EAAYC,GAAqBC,KAPzBC,WACAF,EAAAA,KAAAA,mBAIDG,EAAAA,KAAAA,aAGLF,KAAKC,MAAQ,GACbD,KAAKD,cAAgBA,EACrBC,KAAKE,MAAQ,CACf,CAAC,QAAAC,EAAAL,EAAAM,UAIAN,OAJAK,EAMDE,QAAA,eAAOC,EAAAN,KACL,OAAIA,KAAKO,YACPP,KAAKE,QACEM,QAAQC,eAEJD,QAAQ,SAACC,GAAY,OAAAH,EAAKL,MAAMS,KAAKD,EAAQ,EAE5D,EAACN,EAEDQ,QAAA,WACE,IAAMC,EAAcZ,KAAKC,MAAMY,QAE3BD,EAEFE,WAAWF,EAAa,GAGxBZ,KAAKE,OAET,IAACJ,OAAAiB,IAAA,aAAAC,IAvBD,WACE,OAAOhB,KAAKE,MAAQF,KAAKD,aAC3B,mgBAACD,CAAA,IAwBGmB,EAAa,uCAEJ,WAQb,SAAAC,EAAYnB,QAAAA,IAAAA,IAAAA,EAAwB,GAACC,KAP7BmB,wBAAkB,EAAAnB,KAClBD,mBAON,EAAAC,KAAKmB,mBAAqB,CAAE,EAC5BnB,KAAKD,cAAgBA,CACvB,CAAC,IAAAqB,EAAAF,EAAAd,UA+GA,OA/GAgB,EAEOC,qBAAA,SAAqBN,GAC3B,gBAD2BA,IAAAA,EAAuBE,GAC3CK,QAAQtB,KAAKmB,mBAAmBJ,GACzC,EAACK,EAEOG,qBAAA,SAAqBR,GAI3B,gBAJ2BA,IAAAA,EAAuBE,GAC7CjB,KAAKqB,qBAAqBN,KAC7Bf,KAAKmB,mBAAmBJ,GAAO,IAAIjB,EAAcE,KAAKD,gBAE7CC,KAACmB,mBAAmBJ,EACjC,EAACK,EAMOI,KAAA,SAAKT,QAAAA,IAAAA,IAAAA,EAAuBE,GAEhCjB,KAAKqB,qBAAqBN,IACc,GAAxCf,KAAKuB,qBAAqBR,GAAKb,cAExBF,KAAKmB,mBAAmBJ,EAEnC,EAACK,EASDb,WAAA,SAAWQ,GACT,gBADSA,IAAAA,EAAuBE,GACzBjB,KAAKuB,qBAAqBR,GAAKR,UACxC,EAACa,EAMDf,QAAA,SAAQU,GACN,gBADMA,IAAAA,EAAuBE,GAClBjB,KAACuB,qBAAqBR,GAAKV,SACxC,EAACe,EAMDT,QAAA,SAAQI,QAAAA,IAAAA,IAAAA,EAAuBE,GAC7BjB,KAAKuB,qBAAqBR,GAAKJ,UAC/BX,KAAKwB,KAAKT,EACZ,EAACK,EAODlB,MAAA,SAAMa,GACJ,gBADIA,IAAAA,EAAuBE,GACvBjB,KAAKqB,qBAAqBN,QAChBQ,qBAAqBR,GAAKb,MAGvC,CACH,EAACkB,EAODK,SAAA,SAASV,GACP,gBADOA,IAAAA,EAAuBE,GACvBjB,KAAKE,MAAMa,GAAO,CAC3B,EAACK,EAQKM,QAAOA,SACXC,EACAZ,YAAAA,IAAAA,EAAuBE,GAAU,IAAA,IAAAW,EAGzB5B,KAAIQ,OAAAA,QAAAC,gCADRD,QAAAC,QACImB,EAAKvB,QAAQU,IAAIc,KAAA,WAAA,OAAArB,QAAAC,QACVkB,IACd,4FAFWG,CADR,EAGHC,SAAAA,EAAAC,GACmB,GAAlBJ,EAAKjB,QAAQI,GAAKgB,EAAAC,MAAAA,SAAAA,CAAA,GAEtB,CAAC,MAAAC,GAAAzB,OAAAA,QAAA0B,OAAAD,EAAAb,CAAAA,EAAAA,EAUKe,mBAAkB,SACtBR,EACAZ,QAAAA,IAAAA,IAAAA,EAAuBE,GAAU,IAEjC,OAAIjB,KAAKO,WAAWQ,GAClBP,QAAAC,QADET,KACU0B,QAAQC,EAAIZ,IAExBP,QAAAC,QAAO,KAEX,CAAC,MAAAwB,GAAAzB,OAAAA,QAAA0B,OAAAD,EAAA,CAAA,EAAAf,CAAA,CA1HY"}
|
|
@@ -0,0 +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.count++,Promise.resolve()):new Promise(e=>this.queue.push(e))}release(){const e=this.queue.shift();e?setTimeout(e,0):this.count--}}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}}export{s as default};
|
|
2
|
+
//# sourceMappingURL=promise-semaphore.modern.js.map
|
|
@@ -0,0 +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.count++;\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 // resolveFunc()\n } else {\n this.count--;\n }\n }\n}\n\nconst defaultKey = \"_default\";\n\nclass Semaphore {\n private semaphoreInstances: Record<string | number, SemaphoreItem>;\n private maxConcurrent: number;\n\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 *\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 *\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 *\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 *\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 *\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\nexport default Semaphore;\n"],"names":["SemaphoreItem","constructor","maxConcurrent","queue","count","this","canAcquire","acquire","Promise","resolve","push","release","resolveFunc","shift","setTimeout","defaultKey","Semaphore","semaphoreInstances","hasSemaphoreInstance","key","Boolean","getSemaphoreInstance","tidy","hasTasks","request","fn","requestIfAvailable"],"mappings":"AAAA,MAAMA,EAQJC,WAAAA,CAAYC,GAPJC,KAAAA,WACAD,EAAAA,KAAAA,0BAIDE,WAAK,EAGVC,KAAKF,MAAQ,GACbE,KAAKH,cAAgBA,EACrBG,KAAKD,MAAQ,CACf,CAEA,cAAIE,GACF,YAAYF,MAAQC,KAAKH,aAC3B,CAEAK,OAAAA,GACE,OAAIF,KAAKC,YACPD,KAAKD,QACEI,QAAQC,WAER,IAAID,QAASC,GAAYJ,KAAKF,MAAMO,KAAKD,GAEpD,CAEAE,OAAAA,GACE,MAAMC,EAAcP,KAAKF,MAAMU,QAE3BD,EAEFE,WAAWF,EAAa,GAGxBP,KAAKD,OAET,EAGF,MAAMW,EAAa,WAEnB,MAAMC,EAQJf,WAAAA,CAAYC,EAAwB,GAP5Be,KAAAA,+BACAf,mBAAa,EAOnBG,KAAKY,mBAAqB,CAAA,EAC1BZ,KAAKH,cAAgBA,CACvB,CAEQgB,oBAAAA,CAAqBC,EAAuBJ,GAClD,OAAOK,QAAQf,KAAKY,mBAAmBE,GACzC,CAEQE,oBAAAA,CAAqBF,EAAuBJ,GAIlD,OAHKV,KAAKa,qBAAqBC,KAC7Bd,KAAKY,mBAAmBE,GAAO,IAAInB,EAAcK,KAAKH,gBAEjDG,KAAKY,mBAAmBE,EACjC,CAMQG,IAAAA,CAAKH,EAAuBJ,GAEhCV,KAAKa,qBAAqBC,IACc,GAAxCd,KAAKgB,qBAAqBF,GAAKf,cAExBC,KAAKY,mBAAmBE,EAEnC,CASAb,UAAAA,CAAWa,EAAuBJ,GAChC,OAAWV,KAACgB,qBAAqBF,GAAKb,UACxC,CAMAC,OAAAA,CAAQY,EAAuBJ,GAC7B,OAAOV,KAAKgB,qBAAqBF,GAAKZ,SACxC,CAMAI,OAAAA,CAAQQ,EAAuBJ,GAC7BV,KAAKgB,qBAAqBF,GAAKR,UAC/BN,KAAKiB,KAAKH,EACZ,CAOAf,KAAAA,CAAMe,EAAuBJ,GAC3B,OAAIV,KAAKa,qBAAqBC,GACjBd,KAACgB,qBAAqBF,GAAKf,MAE/B,CAEX,CAOAmB,QAAAA,CAASJ,EAAuBJ,GAC9B,OAAWV,KAACD,MAAMe,GAAO,CAC3B,CAQA,aAAMK,CACJC,EACAN,EAAuBJ,GAEvB,IAEE,aADUV,KAACE,QAAQY,SACNM,GACd,CAAA,QACCpB,KAAKM,QAAQQ,EACd,CACH,CAUA,wBAAMO,CACJD,EACAN,EAAuBJ,GAEvB,OAAIV,KAAKC,WAAWa,GACPd,KAACmB,QAAQC,EAAIN,GAEjB,IAEX"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=/*#__PURE__*/function(){function e(e){this.queue=void 0,this.maxConcurrent=void 0,this.count=void 0,this.queue=[],this.maxConcurrent=e,this.count=0}var t,n,r=e.prototype;return r.acquire=function(){var e=this;return this.canAcquire?(this.count++,Promise.resolve()):new Promise(function(t){return e.queue.push(t)})},r.release=function(){var e=this.queue.shift();e?setTimeout(e,0):this.count--},t=e,(n=[{key:"canAcquire",get:function(){return this.count<this.maxConcurrent}}])&&function(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,"symbol"==typeof(i=function(e,t){if("object"!=typeof e||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,"string");if("object"!=typeof r)return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(r.key))?i:String(i),r)}var i}(t.prototype,n),Object.defineProperty(t,"prototype",{writable:!1}),e}(),t="_default",n=/*#__PURE__*/function(){function n(e){void 0===e&&(e=1),this.semaphoreInstances=void 0,this.maxConcurrent=void 0,this.semaphoreInstances={},this.maxConcurrent=e}var r=n.prototype;return r.hasSemaphoreInstance=function(e){return void 0===e&&(e=t),Boolean(this.semaphoreInstances[e])},r.getSemaphoreInstance=function(n){return void 0===n&&(n=t),this.hasSemaphoreInstance(n)||(this.semaphoreInstances[n]=new e(this.maxConcurrent)),this.semaphoreInstances[n]},r.tidy=function(e){void 0===e&&(e=t),this.hasSemaphoreInstance(e)&&0==this.getSemaphoreInstance(e).count&&delete this.semaphoreInstances[e]},r.canAcquire=function(e){return void 0===e&&(e=t),this.getSemaphoreInstance(e).canAcquire},r.acquire=function(e){return void 0===e&&(e=t),this.getSemaphoreInstance(e).acquire()},r.release=function(e){void 0===e&&(e=t),this.getSemaphoreInstance(e).release(),this.tidy(e)},r.count=function(e){return void 0===e&&(e=t),this.hasSemaphoreInstance(e)?this.getSemaphoreInstance(e).count:0},r.hasTasks=function(e){return void 0===e&&(e=t),this.count(e)>0},r.request=function(e,n){void 0===n&&(n=t);try{var r=this;return Promise.resolve(function(t,i){try{var o=Promise.resolve(r.acquire(n)).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,t){if(r.release(n),e)throw t;return t}))}catch(e){return Promise.reject(e)}},r.requestIfAvailable=function(e,n){void 0===n&&(n=t);try{return this.canAcquire(n)?Promise.resolve(this.request(e,n)):Promise.resolve(null)}catch(e){return Promise.reject(e)}},n}();export{n as default};
|
|
2
|
+
//# sourceMappingURL=promise-semaphore.module.js.map
|
|
@@ -0,0 +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.count++;\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 // resolveFunc()\n } else {\n this.count--;\n }\n }\n}\n\nconst defaultKey = \"_default\";\n\nclass Semaphore {\n private semaphoreInstances: Record<string | number, SemaphoreItem>;\n private maxConcurrent: number;\n\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 *\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 *\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 *\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 *\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 *\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\nexport default Semaphore;\n"],"names":["SemaphoreItem","maxConcurrent","this","queue","count","_proto","prototype","acquire","_this","canAcquire","Promise","resolve","push","release","resolveFunc","shift","setTimeout","key","get","defaultKey","Semaphore","semaphoreInstances","_proto2","hasSemaphoreInstance","Boolean","getSemaphoreInstance","tidy","hasTasks","request","fn","_this2","then","_finallyRethrows","_wasThrown","_result","e","reject","requestIfAvailable"],"mappings":"IAAMA,0BAQJ,SAAAA,EAAYC,GAAqBC,KAPzBC,WACAF,EAAAA,KAAAA,mBAIDG,EAAAA,KAAAA,aAGLF,KAAKC,MAAQ,GACbD,KAAKD,cAAgBA,EACrBC,KAAKE,MAAQ,CACf,CAAC,QAAAC,EAAAL,EAAAM,UAIAN,OAJAK,EAMDE,QAAA,eAAOC,EAAAN,KACL,OAAIA,KAAKO,YACPP,KAAKE,QACEM,QAAQC,eAEJD,QAAQ,SAACC,GAAY,OAAAH,EAAKL,MAAMS,KAAKD,EAAQ,EAE5D,EAACN,EAEDQ,QAAA,WACE,IAAMC,EAAcZ,KAAKC,MAAMY,QAE3BD,EAEFE,WAAWF,EAAa,GAGxBZ,KAAKE,OAET,IAACJ,OAAAiB,IAAA,aAAAC,IAvBD,WACE,OAAOhB,KAAKE,MAAQF,KAAKD,aAC3B,mgBAACD,CAAA,IAwBGmB,EAAa,WAEbC,eAAS,WAQb,SAAAA,EAAYnB,QAAAA,IAAAA,IAAAA,EAAwB,GAACC,KAP7BmB,wBAAkB,EAAAnB,KAClBD,mBAON,EAAAC,KAAKmB,mBAAqB,CAAE,EAC5BnB,KAAKD,cAAgBA,CACvB,CAAC,IAAAqB,EAAAF,EAAAd,UA+GA,OA/GAgB,EAEOC,qBAAA,SAAqBN,GAC3B,gBAD2BA,IAAAA,EAAuBE,GAC3CK,QAAQtB,KAAKmB,mBAAmBJ,GACzC,EAACK,EAEOG,qBAAA,SAAqBR,GAI3B,gBAJ2BA,IAAAA,EAAuBE,GAC7CjB,KAAKqB,qBAAqBN,KAC7Bf,KAAKmB,mBAAmBJ,GAAO,IAAIjB,EAAcE,KAAKD,gBAE7CC,KAACmB,mBAAmBJ,EACjC,EAACK,EAMOI,KAAA,SAAKT,QAAAA,IAAAA,IAAAA,EAAuBE,GAEhCjB,KAAKqB,qBAAqBN,IACc,GAAxCf,KAAKuB,qBAAqBR,GAAKb,cAExBF,KAAKmB,mBAAmBJ,EAEnC,EAACK,EASDb,WAAA,SAAWQ,GACT,gBADSA,IAAAA,EAAuBE,GACzBjB,KAAKuB,qBAAqBR,GAAKR,UACxC,EAACa,EAMDf,QAAA,SAAQU,GACN,gBADMA,IAAAA,EAAuBE,GAClBjB,KAACuB,qBAAqBR,GAAKV,SACxC,EAACe,EAMDT,QAAA,SAAQI,QAAAA,IAAAA,IAAAA,EAAuBE,GAC7BjB,KAAKuB,qBAAqBR,GAAKJ,UAC/BX,KAAKwB,KAAKT,EACZ,EAACK,EAODlB,MAAA,SAAMa,GACJ,gBADIA,IAAAA,EAAuBE,GACvBjB,KAAKqB,qBAAqBN,QAChBQ,qBAAqBR,GAAKb,MAGvC,CACH,EAACkB,EAODK,SAAA,SAASV,GACP,gBADOA,IAAAA,EAAuBE,GACvBjB,KAAKE,MAAMa,GAAO,CAC3B,EAACK,EAQKM,QAAOA,SACXC,EACAZ,YAAAA,IAAAA,EAAuBE,GAAU,IAAA,IAAAW,EAGzB5B,KAAIQ,OAAAA,QAAAC,gCADRD,QAAAC,QACImB,EAAKvB,QAAQU,IAAIc,KAAA,WAAA,OAAArB,QAAAC,QACVkB,IACd,4FAFWG,CADR,EAGHC,SAAAA,EAAAC,GACmB,GAAlBJ,EAAKjB,QAAQI,GAAKgB,EAAAC,MAAAA,SAAAA,CAAA,GAEtB,CAAC,MAAAC,GAAAzB,OAAAA,QAAA0B,OAAAD,EAAAb,CAAAA,EAAAA,EAUKe,mBAAkB,SACtBR,EACAZ,QAAAA,IAAAA,IAAAA,EAAuBE,GAAU,IAEjC,OAAIjB,KAAKO,WAAWQ,GAClBP,QAAAC,QADET,KACU0B,QAAQC,EAAIZ,IAExBP,QAAAC,QAAO,KAEX,CAAC,MAAAwB,GAAAzB,OAAAA,QAAA0B,OAAAD,EAAA,CAAA,EAAAf,CAAA,CA1HY"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e||self).promiseSemaphore=t()}(this,function(){var e=/*#__PURE__*/function(){function e(e){this.queue=void 0,this.maxConcurrent=void 0,this.count=void 0,this.queue=[],this.maxConcurrent=e,this.count=0}var t,n,r=e.prototype;return r.acquire=function(){var e=this;return this.canAcquire?(this.count++,Promise.resolve()):new Promise(function(t){return e.queue.push(t)})},r.release=function(){var e=this.queue.shift();e?setTimeout(e,0):this.count--},t=e,(n=[{key:"canAcquire",get:function(){return this.count<this.maxConcurrent}}])&&function(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,"symbol"==typeof(i=function(e,t){if("object"!=typeof e||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,"string");if("object"!=typeof r)return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(r.key))?i:String(i),r)}var i}(t.prototype,n),Object.defineProperty(t,"prototype",{writable:!1}),e}(),t="_default";/*#__PURE__*/
|
|
2
|
+
return function(){function n(e){void 0===e&&(e=1),this.semaphoreInstances=void 0,this.maxConcurrent=void 0,this.semaphoreInstances={},this.maxConcurrent=e}var r=n.prototype;return r.hasSemaphoreInstance=function(e){return void 0===e&&(e=t),Boolean(this.semaphoreInstances[e])},r.getSemaphoreInstance=function(n){return void 0===n&&(n=t),this.hasSemaphoreInstance(n)||(this.semaphoreInstances[n]=new e(this.maxConcurrent)),this.semaphoreInstances[n]},r.tidy=function(e){void 0===e&&(e=t),this.hasSemaphoreInstance(e)&&0==this.getSemaphoreInstance(e).count&&delete this.semaphoreInstances[e]},r.canAcquire=function(e){return void 0===e&&(e=t),this.getSemaphoreInstance(e).canAcquire},r.acquire=function(e){return void 0===e&&(e=t),this.getSemaphoreInstance(e).acquire()},r.release=function(e){void 0===e&&(e=t),this.getSemaphoreInstance(e).release(),this.tidy(e)},r.count=function(e){return void 0===e&&(e=t),this.hasSemaphoreInstance(e)?this.getSemaphoreInstance(e).count:0},r.hasTasks=function(e){return void 0===e&&(e=t),this.count(e)>0},r.request=function(e,n){void 0===n&&(n=t);try{var r=this;return Promise.resolve(function(t,i){try{var o=Promise.resolve(r.acquire(n)).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,t){if(r.release(n),e)throw t;return t}))}catch(e){return Promise.reject(e)}},r.requestIfAvailable=function(e,n){void 0===n&&(n=t);try{return this.canAcquire(n)?Promise.resolve(this.request(e,n)):Promise.resolve(null)}catch(e){return Promise.reject(e)}},n}()});
|
|
3
|
+
//# sourceMappingURL=promise-semaphore.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promise-semaphore.umd.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.count++;\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 // resolveFunc()\n } else {\n this.count--;\n }\n }\n}\n\nconst defaultKey = \"_default\";\n\nclass Semaphore {\n private semaphoreInstances: Record<string | number, SemaphoreItem>;\n private maxConcurrent: number;\n\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 *\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 *\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 *\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 *\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 *\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\nexport default Semaphore;\n"],"names":["SemaphoreItem","maxConcurrent","this","queue","count","_proto","prototype","acquire","_this","canAcquire","Promise","resolve","push","release","resolveFunc","shift","setTimeout","key","get","defaultKey","Semaphore","semaphoreInstances","_proto2","hasSemaphoreInstance","Boolean","getSemaphoreInstance","tidy","hasTasks","request","fn","_this2","then","_finallyRethrows","_wasThrown","_result","e","reject","requestIfAvailable"],"mappings":"uOAAMA,0BAQJ,SAAAA,EAAYC,GAAqBC,KAPzBC,WACAF,EAAAA,KAAAA,mBAIDG,EAAAA,KAAAA,aAGLF,KAAKC,MAAQ,GACbD,KAAKD,cAAgBA,EACrBC,KAAKE,MAAQ,CACf,CAAC,QAAAC,EAAAL,EAAAM,UAIAN,OAJAK,EAMDE,QAAA,eAAOC,EAAAN,KACL,OAAIA,KAAKO,YACPP,KAAKE,QACEM,QAAQC,eAEJD,QAAQ,SAACC,GAAY,OAAAH,EAAKL,MAAMS,KAAKD,EAAQ,EAE5D,EAACN,EAEDQ,QAAA,WACE,IAAMC,EAAcZ,KAAKC,MAAMY,QAE3BD,EAEFE,WAAWF,EAAa,GAGxBZ,KAAKE,OAET,IAACJ,OAAAiB,IAAA,aAAAC,IAvBD,WACE,OAAOhB,KAAKE,MAAQF,KAAKD,aAC3B,mgBAACD,CAAA,IAwBGmB,EAAa;OAEJ,WAQb,SAAAC,EAAYnB,QAAAA,IAAAA,IAAAA,EAAwB,GAACC,KAP7BmB,wBAAkB,EAAAnB,KAClBD,mBAON,EAAAC,KAAKmB,mBAAqB,CAAE,EAC5BnB,KAAKD,cAAgBA,CACvB,CAAC,IAAAqB,EAAAF,EAAAd,UA+GA,OA/GAgB,EAEOC,qBAAA,SAAqBN,GAC3B,gBAD2BA,IAAAA,EAAuBE,GAC3CK,QAAQtB,KAAKmB,mBAAmBJ,GACzC,EAACK,EAEOG,qBAAA,SAAqBR,GAI3B,gBAJ2BA,IAAAA,EAAuBE,GAC7CjB,KAAKqB,qBAAqBN,KAC7Bf,KAAKmB,mBAAmBJ,GAAO,IAAIjB,EAAcE,KAAKD,gBAE7CC,KAACmB,mBAAmBJ,EACjC,EAACK,EAMOI,KAAA,SAAKT,QAAAA,IAAAA,IAAAA,EAAuBE,GAEhCjB,KAAKqB,qBAAqBN,IACc,GAAxCf,KAAKuB,qBAAqBR,GAAKb,cAExBF,KAAKmB,mBAAmBJ,EAEnC,EAACK,EASDb,WAAA,SAAWQ,GACT,gBADSA,IAAAA,EAAuBE,GACzBjB,KAAKuB,qBAAqBR,GAAKR,UACxC,EAACa,EAMDf,QAAA,SAAQU,GACN,gBADMA,IAAAA,EAAuBE,GAClBjB,KAACuB,qBAAqBR,GAAKV,SACxC,EAACe,EAMDT,QAAA,SAAQI,QAAAA,IAAAA,IAAAA,EAAuBE,GAC7BjB,KAAKuB,qBAAqBR,GAAKJ,UAC/BX,KAAKwB,KAAKT,EACZ,EAACK,EAODlB,MAAA,SAAMa,GACJ,gBADIA,IAAAA,EAAuBE,GACvBjB,KAAKqB,qBAAqBN,QAChBQ,qBAAqBR,GAAKb,MAGvC,CACH,EAACkB,EAODK,SAAA,SAASV,GACP,gBADOA,IAAAA,EAAuBE,GACvBjB,KAAKE,MAAMa,GAAO,CAC3B,EAACK,EAQKM,QAAOA,SACXC,EACAZ,YAAAA,IAAAA,EAAuBE,GAAU,IAAA,IAAAW,EAGzB5B,KAAIQ,OAAAA,QAAAC,gCADRD,QAAAC,QACImB,EAAKvB,QAAQU,IAAIc,KAAA,WAAA,OAAArB,QAAAC,QACVkB,IACd,4FAFWG,CADR,EAGHC,SAAAA,EAAAC,GACmB,GAAlBJ,EAAKjB,QAAQI,GAAKgB,EAAAC,MAAAA,SAAAA,CAAA,GAEtB,CAAC,MAAAC,GAAAzB,OAAAA,QAAA0B,OAAAD,EAAAb,CAAAA,EAAAA,EAUKe,mBAAkB,SACtBR,EACAZ,QAAAA,IAAAA,IAAAA,EAAuBE,GAAU,IAEjC,OAAIjB,KAAKO,WAAWQ,GAClBP,QAAAC,QADET,KACU0B,QAAQC,EAAIZ,IAExBP,QAAAC,QAAO,KAEX,CAAC,MAAAwB,GAAAzB,OAAAA,QAAA0B,OAAAD,EAAA,CAAA,EAAAf,CAAA,CA1HY"}
|
package/package.json
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chriscdn/promise-semaphore",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "Limit or throttle the simultaneous execution of asynchronous code in separate iterations of the event loop.",
|
|
5
|
-
"main": "lib/index.cjs.js",
|
|
6
|
-
"module": "lib/index.es.js",
|
|
7
|
-
"types": "lib/index.d.ts",
|
|
8
5
|
"repository": "https://github.com/chriscdn/promise-semaphore",
|
|
9
6
|
"author": "Christopher Meyer <chris@schwiiz.org>",
|
|
10
7
|
"license": "MIT",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"source": "./src/index.ts",
|
|
10
|
+
"main": "./lib/promise-semaphore.cjs",
|
|
11
|
+
"module": "./lib/promise-semaphore.module.js",
|
|
12
|
+
"unpkg": "./lib/promise-semaphore.umd.js",
|
|
13
|
+
"exports": {
|
|
14
|
+
"require": "./lib/promise-semaphore.cjs",
|
|
15
|
+
"default": "./lib/promise-semaphore.modern.js"
|
|
16
|
+
},
|
|
17
|
+
"types": "./lib/index.d.ts",
|
|
11
18
|
"scripts": {
|
|
12
|
-
"build": "
|
|
13
|
-
"
|
|
14
|
-
"test": "jest"
|
|
19
|
+
"build": "rm -rf ./lib/ && microbundle",
|
|
20
|
+
"dev": "microbundle watch"
|
|
15
21
|
},
|
|
16
22
|
"devDependencies": {
|
|
17
|
-
"
|
|
18
|
-
"esbuild": "^0.17.10",
|
|
19
|
-
"jest": "^29.4.3",
|
|
20
|
-
"rollup": "^3.17.3",
|
|
21
|
-
"rollup-plugin-dts": "^5.2.0",
|
|
22
|
-
"rollup-plugin-esbuild": "^5.0.0",
|
|
23
|
-
"ts-jest": "^29.0.5",
|
|
24
|
-
"typescript": "^4.9.5"
|
|
23
|
+
"microbundle": "^0.15.1"
|
|
25
24
|
},
|
|
26
25
|
"keywords": [
|
|
27
26
|
"promise",
|
package/src/index.ts
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
1
1
|
class SemaphoreItem {
|
|
2
|
-
private queue: Array<Function
|
|
3
|
-
private maxConcurrent: number
|
|
2
|
+
private queue: Array<Function>;
|
|
3
|
+
private maxConcurrent: number;
|
|
4
4
|
/**
|
|
5
5
|
* The number of locks.
|
|
6
6
|
*/
|
|
7
|
-
public count: number
|
|
7
|
+
public count: number;
|
|
8
8
|
|
|
9
9
|
constructor(maxConcurrent: number) {
|
|
10
|
-
this.queue = []
|
|
11
|
-
this.maxConcurrent = maxConcurrent
|
|
12
|
-
this.count = 0
|
|
10
|
+
this.queue = [];
|
|
11
|
+
this.maxConcurrent = maxConcurrent;
|
|
12
|
+
this.count = 0;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
get canAcquire(): boolean {
|
|
16
|
-
return this.count < this.maxConcurrent
|
|
16
|
+
return this.count < this.maxConcurrent;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
acquire(): Promise<void> {
|
|
20
20
|
if (this.canAcquire) {
|
|
21
|
-
this.count
|
|
22
|
-
return Promise.resolve()
|
|
21
|
+
this.count++;
|
|
22
|
+
return Promise.resolve();
|
|
23
23
|
} else {
|
|
24
|
-
return new Promise((resolve) => this.queue.push(resolve))
|
|
24
|
+
return new Promise((resolve) => this.queue.push(resolve));
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
release(): void {
|
|
29
|
-
const resolveFunc = this.queue.shift()
|
|
29
|
+
const resolveFunc = this.queue.shift();
|
|
30
30
|
|
|
31
31
|
if (resolveFunc) {
|
|
32
32
|
// Give the micro task queue a small break instead of calling resolveFunc() directly
|
|
33
|
-
setTimeout(resolveFunc, 0)
|
|
33
|
+
setTimeout(resolveFunc, 0);
|
|
34
34
|
// resolveFunc()
|
|
35
35
|
} else {
|
|
36
|
-
this.count
|
|
36
|
+
this.count--;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
const defaultKey =
|
|
41
|
+
const defaultKey = "_default";
|
|
42
42
|
|
|
43
43
|
class Semaphore {
|
|
44
|
-
private semaphoreInstances: Record<string | number, SemaphoreItem
|
|
45
|
-
private maxConcurrent: number
|
|
44
|
+
private semaphoreInstances: Record<string | number, SemaphoreItem>;
|
|
45
|
+
private maxConcurrent: number;
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
*
|
|
49
49
|
* @param {number} [maxConcurrent] The maximum number of concurrent locks.
|
|
50
50
|
*/
|
|
51
51
|
constructor(maxConcurrent: number = 1) {
|
|
52
|
-
this.semaphoreInstances = {}
|
|
53
|
-
this.maxConcurrent = maxConcurrent
|
|
52
|
+
this.semaphoreInstances = {};
|
|
53
|
+
this.maxConcurrent = maxConcurrent;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
private hasSemaphoreInstance(key: string | number = defaultKey) {
|
|
57
|
-
return Boolean(this.semaphoreInstances[key])
|
|
57
|
+
return Boolean(this.semaphoreInstances[key]);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
private getSemaphoreInstance(key: string | number = defaultKey) {
|
|
61
61
|
if (!this.hasSemaphoreInstance(key)) {
|
|
62
|
-
this.semaphoreInstances[key] = new SemaphoreItem(this.maxConcurrent)
|
|
62
|
+
this.semaphoreInstances[key] = new SemaphoreItem(this.maxConcurrent);
|
|
63
63
|
}
|
|
64
|
-
return this.semaphoreInstances[key]
|
|
64
|
+
return this.semaphoreInstances[key];
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/**
|
|
@@ -73,7 +73,7 @@ class Semaphore {
|
|
|
73
73
|
this.hasSemaphoreInstance(key) &&
|
|
74
74
|
this.getSemaphoreInstance(key).count == 0
|
|
75
75
|
) {
|
|
76
|
-
delete this.semaphoreInstances[key]
|
|
76
|
+
delete this.semaphoreInstances[key];
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
@@ -85,7 +85,7 @@ class Semaphore {
|
|
|
85
85
|
* otherwise.
|
|
86
86
|
*/
|
|
87
87
|
canAcquire(key: string | number = defaultKey): boolean {
|
|
88
|
-
return this.getSemaphoreInstance(key).canAcquire
|
|
88
|
+
return this.getSemaphoreInstance(key).canAcquire;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
/**
|
|
@@ -93,7 +93,7 @@ class Semaphore {
|
|
|
93
93
|
* @param {string | number} [key]- Optional, the semaphore key.
|
|
94
94
|
*/
|
|
95
95
|
acquire(key: string | number = defaultKey) {
|
|
96
|
-
return this.getSemaphoreInstance(key).acquire()
|
|
96
|
+
return this.getSemaphoreInstance(key).acquire();
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
/**
|
|
@@ -101,8 +101,8 @@ class Semaphore {
|
|
|
101
101
|
* @param {string | number} [key]- Optional, the semaphore key.
|
|
102
102
|
*/
|
|
103
103
|
release(key: string | number = defaultKey): void {
|
|
104
|
-
this.getSemaphoreInstance(key).release()
|
|
105
|
-
this.tidy(key)
|
|
104
|
+
this.getSemaphoreInstance(key).release();
|
|
105
|
+
this.tidy(key);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
/**
|
|
@@ -112,9 +112,9 @@ class Semaphore {
|
|
|
112
112
|
*/
|
|
113
113
|
count(key: string | number = defaultKey): number {
|
|
114
114
|
if (this.hasSemaphoreInstance(key)) {
|
|
115
|
-
return this.getSemaphoreInstance(key).count
|
|
115
|
+
return this.getSemaphoreInstance(key).count;
|
|
116
116
|
} else {
|
|
117
|
-
return 0
|
|
117
|
+
return 0;
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
|
|
@@ -124,7 +124,7 @@ class Semaphore {
|
|
|
124
124
|
* @returns {boolean} True if the semaphore and key has locks, false otherwise.
|
|
125
125
|
*/
|
|
126
126
|
hasTasks(key: string | number = defaultKey): boolean {
|
|
127
|
-
return this.count(key) > 0
|
|
127
|
+
return this.count(key) > 0;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
/**
|
|
@@ -138,10 +138,10 @@ class Semaphore {
|
|
|
138
138
|
key: string | number = defaultKey
|
|
139
139
|
): Promise<T> {
|
|
140
140
|
try {
|
|
141
|
-
await this.acquire(key)
|
|
142
|
-
return await fn()
|
|
141
|
+
await this.acquire(key);
|
|
142
|
+
return await fn();
|
|
143
143
|
} finally {
|
|
144
|
-
this.release(key)
|
|
144
|
+
this.release(key);
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
|
|
@@ -158,11 +158,11 @@ class Semaphore {
|
|
|
158
158
|
key: string | number = defaultKey
|
|
159
159
|
): Promise<T | null> {
|
|
160
160
|
if (this.canAcquire(key)) {
|
|
161
|
-
return this.request(fn, key)
|
|
161
|
+
return this.request(fn, key);
|
|
162
162
|
} else {
|
|
163
|
-
return null
|
|
163
|
+
return null;
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
export default Semaphore
|
|
168
|
+
export default Semaphore;
|
package/.prettierrc
DELETED
package/lib/index.cjs.js
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
class SemaphoreItem {
|
|
4
|
-
queue;
|
|
5
|
-
maxConcurrent;
|
|
6
|
-
/**
|
|
7
|
-
* The number of locks.
|
|
8
|
-
*/
|
|
9
|
-
count;
|
|
10
|
-
constructor(maxConcurrent) {
|
|
11
|
-
this.queue = [];
|
|
12
|
-
this.maxConcurrent = maxConcurrent;
|
|
13
|
-
this.count = 0;
|
|
14
|
-
}
|
|
15
|
-
get canAcquire() {
|
|
16
|
-
return this.count < this.maxConcurrent;
|
|
17
|
-
}
|
|
18
|
-
acquire() {
|
|
19
|
-
if (this.canAcquire) {
|
|
20
|
-
this.count++;
|
|
21
|
-
return Promise.resolve();
|
|
22
|
-
} else {
|
|
23
|
-
return new Promise((resolve) => this.queue.push(resolve));
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
release() {
|
|
27
|
-
const resolveFunc = this.queue.shift();
|
|
28
|
-
if (resolveFunc) {
|
|
29
|
-
setTimeout(resolveFunc, 0);
|
|
30
|
-
} else {
|
|
31
|
-
this.count--;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
const defaultKey = "_default";
|
|
36
|
-
class Semaphore {
|
|
37
|
-
semaphoreInstances;
|
|
38
|
-
maxConcurrent;
|
|
39
|
-
/**
|
|
40
|
-
*
|
|
41
|
-
* @param {number} [maxConcurrent] The maximum number of concurrent locks.
|
|
42
|
-
*/
|
|
43
|
-
constructor(maxConcurrent = 1) {
|
|
44
|
-
this.semaphoreInstances = {};
|
|
45
|
-
this.maxConcurrent = maxConcurrent;
|
|
46
|
-
}
|
|
47
|
-
hasSemaphoreInstance(key = defaultKey) {
|
|
48
|
-
return Boolean(this.semaphoreInstances[key]);
|
|
49
|
-
}
|
|
50
|
-
getSemaphoreInstance(key = defaultKey) {
|
|
51
|
-
if (!this.hasSemaphoreInstance(key)) {
|
|
52
|
-
this.semaphoreInstances[key] = new SemaphoreItem(this.maxConcurrent);
|
|
53
|
-
}
|
|
54
|
-
return this.semaphoreInstances[key];
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
*
|
|
58
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
59
|
-
*/
|
|
60
|
-
tidy(key = defaultKey) {
|
|
61
|
-
if (this.hasSemaphoreInstance(key) && this.getSemaphoreInstance(key).count == 0) {
|
|
62
|
-
delete this.semaphoreInstances[key];
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* A synchronous function to determine whether a lock can be acquired.
|
|
67
|
-
*
|
|
68
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
69
|
-
* @returns {boolean} Returns true if the lock on `key` can be acquired, false
|
|
70
|
-
* otherwise.
|
|
71
|
-
*/
|
|
72
|
-
canAcquire(key = defaultKey) {
|
|
73
|
-
return this.getSemaphoreInstance(key).canAcquire;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
*
|
|
77
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
78
|
-
*/
|
|
79
|
-
acquire(key = defaultKey) {
|
|
80
|
-
return this.getSemaphoreInstance(key).acquire();
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
*
|
|
84
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
85
|
-
*/
|
|
86
|
-
release(key = defaultKey) {
|
|
87
|
-
this.getSemaphoreInstance(key).release();
|
|
88
|
-
this.tidy(key);
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* The number of active locks. Will always be less or equal to `max`.
|
|
92
|
-
*
|
|
93
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
94
|
-
*/
|
|
95
|
-
count(key = defaultKey) {
|
|
96
|
-
if (this.hasSemaphoreInstance(key)) {
|
|
97
|
-
return this.getSemaphoreInstance(key).count;
|
|
98
|
-
} else {
|
|
99
|
-
return 0;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
*
|
|
104
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
105
|
-
* @returns {boolean} True if the semaphore and key has locks, false otherwise.
|
|
106
|
-
*/
|
|
107
|
-
hasTasks(key = defaultKey) {
|
|
108
|
-
return this.count(key) > 0;
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
*
|
|
112
|
-
* @param {Function<T>} fn The function to execute.
|
|
113
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
114
|
-
* @returns {Promise<T>}
|
|
115
|
-
*/
|
|
116
|
-
async request(fn, key = defaultKey) {
|
|
117
|
-
try {
|
|
118
|
-
await this.acquire(key);
|
|
119
|
-
return await fn();
|
|
120
|
-
} finally {
|
|
121
|
-
this.release(key);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Asynchronously executes `fn` if a lock can be immediately acquired.
|
|
126
|
-
* Otherwise, returns null.
|
|
127
|
-
*
|
|
128
|
-
* @param {Function<T>} fn The function to execute.
|
|
129
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
130
|
-
* @returns {Promise<T>}
|
|
131
|
-
*/
|
|
132
|
-
async requestIfAvailable(fn, key = defaultKey) {
|
|
133
|
-
if (this.canAcquire(key)) {
|
|
134
|
-
return this.request(fn, key);
|
|
135
|
-
} else {
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
module.exports = Semaphore;
|
package/lib/index.es.js
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
class SemaphoreItem {
|
|
2
|
-
queue;
|
|
3
|
-
maxConcurrent;
|
|
4
|
-
/**
|
|
5
|
-
* The number of locks.
|
|
6
|
-
*/
|
|
7
|
-
count;
|
|
8
|
-
constructor(maxConcurrent) {
|
|
9
|
-
this.queue = [];
|
|
10
|
-
this.maxConcurrent = maxConcurrent;
|
|
11
|
-
this.count = 0;
|
|
12
|
-
}
|
|
13
|
-
get canAcquire() {
|
|
14
|
-
return this.count < this.maxConcurrent;
|
|
15
|
-
}
|
|
16
|
-
acquire() {
|
|
17
|
-
if (this.canAcquire) {
|
|
18
|
-
this.count++;
|
|
19
|
-
return Promise.resolve();
|
|
20
|
-
} else {
|
|
21
|
-
return new Promise((resolve) => this.queue.push(resolve));
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
release() {
|
|
25
|
-
const resolveFunc = this.queue.shift();
|
|
26
|
-
if (resolveFunc) {
|
|
27
|
-
setTimeout(resolveFunc, 0);
|
|
28
|
-
} else {
|
|
29
|
-
this.count--;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
const defaultKey = "_default";
|
|
34
|
-
class Semaphore {
|
|
35
|
-
semaphoreInstances;
|
|
36
|
-
maxConcurrent;
|
|
37
|
-
/**
|
|
38
|
-
*
|
|
39
|
-
* @param {number} [maxConcurrent] The maximum number of concurrent locks.
|
|
40
|
-
*/
|
|
41
|
-
constructor(maxConcurrent = 1) {
|
|
42
|
-
this.semaphoreInstances = {};
|
|
43
|
-
this.maxConcurrent = maxConcurrent;
|
|
44
|
-
}
|
|
45
|
-
hasSemaphoreInstance(key = defaultKey) {
|
|
46
|
-
return Boolean(this.semaphoreInstances[key]);
|
|
47
|
-
}
|
|
48
|
-
getSemaphoreInstance(key = defaultKey) {
|
|
49
|
-
if (!this.hasSemaphoreInstance(key)) {
|
|
50
|
-
this.semaphoreInstances[key] = new SemaphoreItem(this.maxConcurrent);
|
|
51
|
-
}
|
|
52
|
-
return this.semaphoreInstances[key];
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
*
|
|
56
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
57
|
-
*/
|
|
58
|
-
tidy(key = defaultKey) {
|
|
59
|
-
if (this.hasSemaphoreInstance(key) && this.getSemaphoreInstance(key).count == 0) {
|
|
60
|
-
delete this.semaphoreInstances[key];
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* A synchronous function to determine whether a lock can be acquired.
|
|
65
|
-
*
|
|
66
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
67
|
-
* @returns {boolean} Returns true if the lock on `key` can be acquired, false
|
|
68
|
-
* otherwise.
|
|
69
|
-
*/
|
|
70
|
-
canAcquire(key = defaultKey) {
|
|
71
|
-
return this.getSemaphoreInstance(key).canAcquire;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
*
|
|
75
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
76
|
-
*/
|
|
77
|
-
acquire(key = defaultKey) {
|
|
78
|
-
return this.getSemaphoreInstance(key).acquire();
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
*
|
|
82
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
83
|
-
*/
|
|
84
|
-
release(key = defaultKey) {
|
|
85
|
-
this.getSemaphoreInstance(key).release();
|
|
86
|
-
this.tidy(key);
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* The number of active locks. Will always be less or equal to `max`.
|
|
90
|
-
*
|
|
91
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
92
|
-
*/
|
|
93
|
-
count(key = defaultKey) {
|
|
94
|
-
if (this.hasSemaphoreInstance(key)) {
|
|
95
|
-
return this.getSemaphoreInstance(key).count;
|
|
96
|
-
} else {
|
|
97
|
-
return 0;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
*
|
|
102
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
103
|
-
* @returns {boolean} True if the semaphore and key has locks, false otherwise.
|
|
104
|
-
*/
|
|
105
|
-
hasTasks(key = defaultKey) {
|
|
106
|
-
return this.count(key) > 0;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
*
|
|
110
|
-
* @param {Function<T>} fn The function to execute.
|
|
111
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
112
|
-
* @returns {Promise<T>}
|
|
113
|
-
*/
|
|
114
|
-
async request(fn, key = defaultKey) {
|
|
115
|
-
try {
|
|
116
|
-
await this.acquire(key);
|
|
117
|
-
return await fn();
|
|
118
|
-
} finally {
|
|
119
|
-
this.release(key);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Asynchronously executes `fn` if a lock can be immediately acquired.
|
|
124
|
-
* Otherwise, returns null.
|
|
125
|
-
*
|
|
126
|
-
* @param {Function<T>} fn The function to execute.
|
|
127
|
-
* @param {string | number} [key]- Optional, the semaphore key.
|
|
128
|
-
* @returns {Promise<T>}
|
|
129
|
-
*/
|
|
130
|
-
async requestIfAvailable(fn, key = defaultKey) {
|
|
131
|
-
if (this.canAcquire(key)) {
|
|
132
|
-
return this.request(fn, key);
|
|
133
|
-
} else {
|
|
134
|
-
return null;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export { Semaphore as default };
|
package/rollup.config.mjs
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import pkg from './package.json' assert { type: 'json' }
|
|
2
|
-
import dts from 'rollup-plugin-dts'
|
|
3
|
-
import esbuild from 'rollup-plugin-esbuild'
|
|
4
|
-
|
|
5
|
-
const input = 'src/index.ts'
|
|
6
|
-
|
|
7
|
-
export default [
|
|
8
|
-
{
|
|
9
|
-
input,
|
|
10
|
-
plugins: [esbuild()],
|
|
11
|
-
output: [
|
|
12
|
-
{
|
|
13
|
-
file: pkg.main,
|
|
14
|
-
format: 'cjs',
|
|
15
|
-
// sourcemap: true,
|
|
16
|
-
// exports: 'default',
|
|
17
|
-
},
|
|
18
|
-
],
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
input,
|
|
22
|
-
plugins: [esbuild()],
|
|
23
|
-
output: [
|
|
24
|
-
{
|
|
25
|
-
file: pkg.module,
|
|
26
|
-
format: 'es',
|
|
27
|
-
// sourcemap: true,
|
|
28
|
-
// exports: 'default',
|
|
29
|
-
},
|
|
30
|
-
],
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
input,
|
|
34
|
-
plugins: [dts()],
|
|
35
|
-
output: {
|
|
36
|
-
file: 'lib/index.d.ts',
|
|
37
|
-
format: 'es',
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
]
|