@chriscdn/promise-semaphore 2.0.9 → 2.0.10

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 CHANGED
@@ -16,10 +16,6 @@ Using yarn:
16
16
  yarn add @chriscdn/promise-semaphore
17
17
  ```
18
18
 
19
- ## Updating v1 to v2
20
-
21
- Version 2 adds TypeScript and better inline documentation. The API remains the same, and doesn't introduce any breaking changes.
22
-
23
19
  ## API
24
20
 
25
21
  ### Create an instance
@@ -29,7 +25,7 @@ import Semaphore from "@chriscdn/promise-semaphore";
29
25
  const semaphore = new Semaphore([maxConcurrent]);
30
26
  ```
31
27
 
32
- The `maxConcurrent` parameter is optional, and defaults to `1` (making it an exclusive lock or _binary semaphore_). Use an integer value greater than one to limit how many times the code block can be simultaneously executing from separate iterations of the event loop.
28
+ The `maxConcurrent` parameter is optional and defaults to `1` (making it an exclusive lock or _binary semaphore_). An integer greater than `1` can be used to allow multiple concurrent executions from separate iterations of the event loop.
33
29
 
34
30
  ### Acquire a lock
35
31
 
@@ -37,7 +33,7 @@ The `maxConcurrent` parameter is optional, and defaults to `1` (making it an exc
37
33
  semaphore.acquire([key]);
38
34
  ```
39
35
 
40
- This returns a `Promise`, which resolves once a lock has been acquired. The `key` parameter is optional and permits the same `Semaphore` instance to be used in different contexts. See the second example.
36
+ This returns a `Promise` that resolves once a lock is acquired. The `key` parameter is optional and allows the same `Semaphore` instance to manage locks in different contexts. Additional details are provided in the second example.
41
37
 
42
38
  ### Release a lock
43
39
 
@@ -45,7 +41,7 @@ This returns a `Promise`, which resolves once a lock has been acquired. The `key
45
41
  semaphore.release([key]);
46
42
  ```
47
43
 
48
- The `release` call should be executed from a `finally` block (whether using promises or a try/catch block) to guarantee it gets called.
44
+ The `release` method should be called within a `finally` block (whether using promises or a `try/catch` block) to ensure the lock is released.
49
45
 
50
46
  ### Check if a lock can be acquired
51
47
 
@@ -53,15 +49,15 @@ The `release` call should be executed from a `finally` block (whether using prom
53
49
  semaphore.canAcquire([key]);
54
50
  ```
55
51
 
56
- This method is synchronous, and returns `true` if a lock can be immediately acquired, `false` otherwise.
52
+ This synchronous method returns `true` if a lock can be immediately acquired, and `false` otherwise.
57
53
 
58
- ### request function
54
+ ### `request` function
59
55
 
60
56
  ```js
61
- const results = await semaphore.request(fn [,key])
57
+ const results = await semaphore.request(fn [, key]);
62
58
  ```
63
59
 
64
- This function reduces boilerplate when using `acquire` and `release`. It returns a promise, which resolves once `fn` has completed. It is functionally equivalent to:
60
+ This function reduces boilerplate when using `acquire` and `release`. It returns a promise that resolves when `fn` completes. It is functionally equivalent to:
65
61
 
66
62
  ```js
67
63
  try {
@@ -72,23 +68,21 @@ try {
72
68
  }
73
69
  ```
74
70
 
75
- See the examples below.
76
-
77
- ### requestIfAvailable function
71
+ ### `requestIfAvailable` function
78
72
 
79
73
  ```js
80
- const results = await semaphore.requestIfAvailable(fn [,key])
74
+ const results = await semaphore.requestIfAvailable(fn [, key]);
81
75
  ```
82
76
 
83
77
  This is functionally equivalent to:
84
78
 
85
79
  ```js
86
- const results = semaphore.canAcquire([key] ?
87
- await semaphore.request(fn, [key]) :
88
- null
80
+ const results = semaphore.canAcquire([key])
81
+ ? await semaphore.request(fn, [key])
82
+ : null;
89
83
  ```
90
84
 
91
- This is useful in situations when only one instance of a function block should run, while discarding other attempts to execute the block. E.g., a button is repeatedly clicked.
85
+ This is useful in scenarios where only one instance of a function block should run while discarding additional attempts. For example, handling repeated button clicks.
92
86
 
93
87
  ## Example 1
94
88
 
@@ -96,66 +90,66 @@ This is useful in situations when only one instance of a function block should r
96
90
  import Semaphore from "@chriscdn/promise-semaphore";
97
91
  const semaphore = new Semaphore();
98
92
 
99
- // using promises
93
+ // Using promises
100
94
  semaphore
101
95
  .acquire()
102
96
  .then(() => {
103
- // This block executes once a lock is acquired. If already locked,
104
- // then wait and execute once all preceeding locks have been released.
97
+ // This block executes once a lock is acquired.
98
+ // If already locked, it waits and executes after all preceding locks are released.
105
99
  //
106
- // do your critical stuff here
100
+ // Critical operations are performed here.
107
101
  })
108
102
  .finally(() => {
109
- // release the lock permitting the next queued block to continue
103
+ // The lock is released, allowing the next queued block to proceed.
110
104
  semaphore.release();
111
105
  });
112
106
 
113
- // or, using async/await
107
+ // Using async/await
114
108
  try {
115
109
  await semaphore.acquire();
116
110
 
117
- // do your critical stuff here
111
+ // Critical operations are performed here.
118
112
  } finally {
119
113
  semaphore.release();
120
114
  }
121
115
 
122
- // or, using the request function
123
- semaphore.request(() => {
124
- // do your critical stuff here
116
+ // Using the request function
117
+ await semaphore.request(() => {
118
+ // Critical operations are performed here.
125
119
  });
126
120
  ```
127
121
 
128
122
  ## Example 2
129
123
 
130
- Say you have an asynchronous function to download a file and save it to disk:
124
+ Consider an asynchronous function that downloads a file and saves it to disk:
131
125
 
132
126
  ```js
133
- async function downloadAndSave(url) {
127
+ const downloadAndSave = async (url) => {
134
128
  const filePath = urlToFilePath(url);
135
129
 
136
130
  if (await pathExists(filePath)) {
137
- // the file is on disk, so no action is required
138
- } else {
139
- await downloadAndSaveToFilepath(url, filePath);
131
+ // The file is already on disk, so no action is required.
132
+ return filePath;
140
133
  }
141
134
 
135
+ await downloadAndSaveToFilepath(url, filePath);
142
136
  return filePath;
143
- }
137
+ };
144
138
  ```
145
139
 
146
- This works until a process calls `downloadAndSave()` multiple times in short succession with the same `url`. This can cause multiple simultaneous downloads that attempt to write to the same file at the same time.
140
+ This approach works as expected until `downloadAndSave()` is called multiple times with the same `url` in quick succession. Without control, it could initiate simultaneous downloads that attempt to write to the same file at the same time.
147
141
 
148
- This can be resolved with a `Semaphore` instance using the `key` parameter:
142
+ This issue can be resolved by using a `Semaphore` with the `key` parameter:
149
143
 
150
144
  ```js
151
145
  import Semaphore from "@chriscdn/promise-semaphore";
152
146
  const semaphore = new Semaphore();
153
147
 
154
- async function downloadAndSave(url) {
148
+ const downloadAndSave = async (url) => {
155
149
  try {
156
150
  await semaphore.acquire(url);
157
151
 
158
- // This block continues once a lock on url is acquired. This
152
+ // This block continues once a lock on url is acquired. This
159
153
  // permits multiple simulataneous downloads for different urls.
160
154
 
161
155
  const filePath = urlToFilePath(url);
@@ -170,27 +164,26 @@ async function downloadAndSave(url) {
170
164
  } finally {
171
165
  semaphore.release(url);
172
166
  }
173
- }
167
+ };
174
168
  ```
175
169
 
176
- Alternatively, this can be accomplished with the `request` function:
170
+ The same outcome can be achieved using the `request` function:
177
171
 
178
172
  ```js
179
- async function downloadAndSave(url) {
180
-
181
- return semaphore.request(() => {
182
- const filePath = urlToFilePath(url)
173
+ const downloadAndSave = (url) => {
174
+ return semaphore.request(async () => {
175
+ const filePath = urlToFilePath(url);
183
176
 
184
177
  if (await pathExists(filePath)) {
185
- // the file is on disk, so no action is required
186
- } else {
187
- await downloadAndSaveToFilepath(url, filePath)
178
+ // The file is already on disk, so no action is required.
179
+ return filePath;
188
180
  }
189
181
 
190
- return filePath
191
- }, url)
182
+ await downloadAndSaveToFilepath(url, filePath);
192
183
 
193
- }
184
+ return filePath;
185
+ }, url);
186
+ };
194
187
  ```
195
188
 
196
189
  ## License
@@ -1,143 +1,147 @@
1
+ import { describe, expect, test } from "vitest";
2
+
1
3
  import Semaphore from "../src/index";
2
4
 
3
5
  const pause = async (ms) => new Promise((resolve) => setTimeout(resolve, ms));
4
6
 
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
- });
7
+ describe("All test", () => {
8
+ test("Acquire & Release Basic", async () => {
9
+ const semaphore = new Semaphore();
10
+ expect(semaphore.canAcquire()).toBe(true);
11
+ await semaphore.acquire();
12
+ expect(semaphore.canAcquire()).toBe(false);
13
+ expect(semaphore.hasTasks()).toBe(true);
14
+ expect(semaphore.count()).toBe(1);
15
+ semaphore.release();
16
+ expect(semaphore.canAcquire()).toBe(true);
17
+ expect(semaphore.count()).toBe(0);
18
+ });
16
19
 
17
- test("Semaphore 1", async () => {
18
- const semaphore = new Semaphore();
20
+ test("Semaphore 1", async () => {
21
+ const semaphore = new Semaphore();
19
22
 
20
- semaphore
21
- .acquire()
22
- .then(async () => await pause(1000))
23
- .finally(() => semaphore.release());
23
+ semaphore
24
+ .acquire()
25
+ .then(async () => await pause(1000))
26
+ .finally(() => semaphore.release());
24
27
 
25
- expect(semaphore.canAcquire()).toBe(false);
28
+ expect(semaphore.canAcquire()).toBe(false);
26
29
 
27
- await pause(600);
30
+ await pause(600);
28
31
 
29
- expect(semaphore.canAcquire()).toBe(false);
32
+ expect(semaphore.canAcquire()).toBe(false);
30
33
 
31
- await pause(600);
34
+ await pause(600);
32
35
 
33
- expect(semaphore.canAcquire()).toBe(true);
34
- });
36
+ expect(semaphore.canAcquire()).toBe(true);
37
+ });
35
38
 
36
- test("Semaphore 2", async () => {
37
- const semaphore = new Semaphore();
39
+ test("Semaphore 2", async () => {
40
+ const semaphore = new Semaphore();
38
41
 
39
- let tester = 0;
42
+ let tester = 0;
40
43
 
41
- semaphore
42
- .acquire()
43
- .then(() => pause(1000))
44
- .then(() => (tester = 10))
45
- .finally(() => semaphore.release());
44
+ semaphore
45
+ .acquire()
46
+ .then(() => pause(1000))
47
+ .then(() => (tester = 10))
48
+ .finally(() => semaphore.release());
46
49
 
47
- // tests acquire waits for previous to complete
48
- await semaphore
49
- .acquire()
50
- .then(() => expect(tester).toBe(10))
51
- .finally(() => semaphore.release());
52
- });
50
+ // tests acquire waits for previous to complete
51
+ await semaphore
52
+ .acquire()
53
+ .then(() => expect(tester).toBe(10))
54
+ .finally(() => semaphore.release());
55
+ });
53
56
 
54
- test("Semaphore 3", async () => {
55
- const semaphore = new Semaphore(2);
57
+ test("Semaphore 3", async () => {
58
+ const semaphore = new Semaphore(2);
56
59
 
57
- let tester = 0;
60
+ let tester = 0;
58
61
 
59
- semaphore
60
- .acquire()
61
- .then(() => pause(1000))
62
- .then(() => (tester = 20))
63
- .finally(() => semaphore.release());
62
+ semaphore
63
+ .acquire()
64
+ .then(() => pause(1000))
65
+ .then(() => (tester = 20))
66
+ .finally(() => semaphore.release());
64
67
 
65
- semaphore
66
- .acquire()
67
- .then(() => pause(500))
68
- .then(() => (tester = 10))
69
- .finally(() => semaphore.release());
68
+ semaphore
69
+ .acquire()
70
+ .then(() => pause(500))
71
+ .then(() => (tester = 10))
72
+ .finally(() => semaphore.release());
70
73
 
71
- expect(semaphore.count()).toBe(2);
72
- expect(semaphore.hasTasks()).toBe(true);
74
+ expect(semaphore.count()).toBe(2);
75
+ expect(semaphore.hasTasks()).toBe(true);
73
76
 
74
- // expect 10 since this next block will run before the first has completed
75
- await semaphore
76
- .acquire()
77
- .then(() => expect(tester).toBe(10))
78
- .finally(() => semaphore.release());
77
+ // expect 10 since this next block will run before the first has completed
78
+ await semaphore
79
+ .acquire()
80
+ .then(() => expect(tester).toBe(10))
81
+ .finally(() => semaphore.release());
79
82
 
80
- expect(semaphore.count()).toBe(1);
81
- expect(semaphore.hasTasks()).toBe(true);
82
- expect(semaphore.canAcquire()).toBe(true);
83
- });
83
+ expect(semaphore.count()).toBe(1);
84
+ expect(semaphore.hasTasks()).toBe(true);
85
+ expect(semaphore.canAcquire()).toBe(true);
86
+ });
84
87
 
85
- test("Request 1", async () => {
86
- const semaphore = new Semaphore();
88
+ test("Request 1", async () => {
89
+ const semaphore = new Semaphore();
87
90
 
88
- let tester = 0;
91
+ let tester = 0;
89
92
 
90
- semaphore.request(async () => {
91
- await pause(1000);
92
- tester = 20;
93
- });
93
+ semaphore.request(async () => {
94
+ await pause(1000);
95
+ tester = 20;
96
+ });
94
97
 
95
- semaphore.request(async () => {
96
- await pause(500);
97
- tester = 10;
98
- });
98
+ semaphore.request(async () => {
99
+ await pause(500);
100
+ tester = 10;
101
+ });
99
102
 
100
- await semaphore.request(async () => {
101
- expect(tester).toBe(10);
103
+ await semaphore.request(async () => {
104
+ expect(tester).toBe(10);
105
+ });
102
106
  });
103
- });
104
107
 
105
- test("Request 2", async () => {
106
- const semaphore = new Semaphore(2);
108
+ test("Request 2", async () => {
109
+ const semaphore = new Semaphore(2);
107
110
 
108
- let tester = 0;
111
+ let tester = 0;
109
112
 
110
- semaphore.request(async () => {
111
- await pause(1000);
112
- tester = 20;
113
- });
113
+ semaphore.request(async () => {
114
+ await pause(1000);
115
+ tester = 20;
116
+ });
114
117
 
115
- semaphore.request(async () => {
116
- await pause(500);
117
- tester = 10;
118
- });
118
+ semaphore.request(async () => {
119
+ await pause(500);
120
+ tester = 10;
121
+ });
119
122
 
120
- await semaphore.request(async () => {
121
- expect(tester).toBe(10);
123
+ await semaphore.request(async () => {
124
+ expect(tester).toBe(10);
125
+ });
122
126
  });
123
- });
124
127
 
125
- test("Request 3", async () => {
126
- const semaphore = new Semaphore(3);
128
+ test("Request 3", async () => {
129
+ const semaphore = new Semaphore(3);
127
130
 
128
- let tester = 0;
131
+ let tester = 0;
129
132
 
130
- semaphore.request(async () => {
131
- await pause(1000);
132
- tester = 20;
133
- });
133
+ semaphore.request(async () => {
134
+ await pause(1000);
135
+ tester = 20;
136
+ });
134
137
 
135
- semaphore.request(async () => {
136
- await pause(500);
137
- tester = 10;
138
- });
138
+ semaphore.request(async () => {
139
+ await pause(500);
140
+ tester = 10;
141
+ });
139
142
 
140
- await semaphore.request(async () => {
141
- expect(tester).toBe(0);
143
+ await semaphore.request(async () => {
144
+ expect(tester).toBe(0);
145
+ });
142
146
  });
143
147
  });
@@ -1,2 +1,2 @@
1
- function e(e){var t=function(e,t){if("object"!=typeof e||!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)}(e);return"symbol"==typeof t?t:String(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.count++,Promise.resolve()):new Promise(function(t){return e.queue.push(t)})},i.release=function(){var e=this.queue.shift();e?setTimeout(e,0):this.count--},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}),t}(),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)}},e}();
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.count++,Promise.resolve()):new Promise(function(t){return e.queue.push(t)})},i.release=function(){var e=this.queue.shift();e?setTimeout(e,0):this.count--},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)}},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.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":"0SAAMA,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,gPAACD,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,IACe,IAAzCf,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"}
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","queue","this","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":"mSAAMA,eAQJ,WAAA,SAAAA,EAAYC,QAPJC,WAAK,EAAAC,KACLF,mBAIDG,EAAAA,KAAAA,WAGL,EAAAD,KAAKD,MAAQ,GACbC,KAAKF,cAAgBA,EACrBE,KAAKC,MAAQ,CACf,CAAC,QAAAC,EAAAL,EAAAM,iBAAAD,EAMDE,QAAA,WAAO,IAAAC,EACLL,KAAA,OAAIA,KAAKM,YACPN,KAAKC,QACEM,QAAQC,WAER,IAAID,QAAQ,SAACC,GAAO,OAAKH,EAAKN,MAAMU,KAAKD,EAAQ,EAE5D,EAACN,EAEDQ,QAAA,WACE,IAAMC,EAAcX,KAAKD,MAAMa,QAE3BD,EAEFE,WAAWF,EAAa,GAGxBX,KAAKC,OAET,IAACJ,KAAA,CAAA,CAAAiB,IAAAC,aAAAA,IAvBD,WACE,OAAWf,KAACC,MAAQD,KAAKF,aAC3B,kPARA,GAgCIkB,EAAa,uCAEJ,WAQb,SAAAC,EAAYnB,QAAAA,IAAAA,IAAAA,EAAwB,GAACE,KAP7BkB,wBACApB,EAAAA,KAAAA,qBAONE,KAAKkB,mBAAqB,GAC1BlB,KAAKF,cAAgBA,CACvB,CAAC,IAAAqB,EAAAF,EAAAd,UA+GA,OA/GAgB,EAEOC,qBAAA,SAAqBN,GAC3B,YAD2BA,IAAAA,IAAAA,EAAuBE,GAC3CK,QAAQrB,KAAKkB,mBAAmBJ,GACzC,EAACK,EAEOG,qBAAA,SAAqBR,GAI3B,gBAJ2BA,IAAAA,EAAuBE,GAC7ChB,KAAKoB,qBAAqBN,KAC7Bd,KAAKkB,mBAAmBJ,GAAO,IAAIjB,EAAcG,KAAKF,qBAE5CoB,mBAAmBJ,EACjC,EAACK,EAMOI,KAAA,SAAKT,YAAAA,IAAAA,EAAuBE,GAEhChB,KAAKoB,qBAAqBN,IACe,IAAzCd,KAAKsB,qBAAqBR,GAAKb,cAEpBD,KAACkB,mBAAmBJ,EAEnC,EAACK,EASDb,WAAA,SAAWQ,GACT,gBADSA,IAAAA,EAAuBE,GACzBhB,KAAKsB,qBAAqBR,GAAKR,UACxC,EAACa,EAMDf,QAAA,SAAQU,GACN,gBADMA,IAAAA,EAAuBE,GAClBhB,KAACsB,qBAAqBR,GAAKV,SACxC,EAACe,EAMDT,QAAA,SAAQI,YAAAA,IAAAA,EAAuBE,GAC7BhB,KAAKsB,qBAAqBR,GAAKJ,UAC/BV,KAAKuB,KAAKT,EACZ,EAACK,EAODlB,MAAA,SAAMa,GACJ,YADIA,IAAAA,IAAAA,EAAuBE,GACvBhB,KAAKoB,qBAAqBN,GACrBd,KAAKsB,qBAAqBR,GAAKb,MAE/B,CAEX,EAACkB,EAODK,SAAA,SAASV,GACP,YADOA,IAAAA,IAAAA,EAAuBE,GACnBhB,KAACC,MAAMa,GAAO,CAC3B,EAACK,EAQKM,iBACJC,EACAZ,QAAAA,IAAAA,IAAAA,EAAuBE,GAAU,IAAAW,IAAAA,EAGzB3B,KAAI,OAAAO,QAAAC,gCADRD,QAAAC,QACImB,EAAKvB,QAAQU,IAAIc,uBAAArB,QAAAC,QACVkB,IAAI,4FADPG,CAAA,EAEXC,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,YAAAA,IAAAA,EAAuBE,GAAU,IAEjC,OAAIhB,KAAKM,WAAWQ,GAClBP,QAAAC,QADER,KACUyB,QAAQC,EAAIZ,IAExBP,QAAAC,QAAO,KAEX,CAAC,MAAAwB,GAAA,OAAAzB,QAAA0B,OAAAD,EAAA,CAAA,EAAAf,CAAA,CA1HY"}
@@ -1,2 +1,2 @@
1
- function e(e){var t=function(e,t){if("object"!=typeof e||!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)}(e);return"symbol"==typeof t?t:String(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.count++,Promise.resolve()):new Promise(function(t){return e.queue.push(t)})},i.release=function(){var e=this.queue.shift();e?setTimeout(e,0):this.count--},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}),t}(),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)}},e}();export{r as default};
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.count++,Promise.resolve()):new Promise(function(t){return e.queue.push(t)})},i.release=function(){var e=this.queue.shift();e?setTimeout(e,0):this.count--},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)}},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.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":"0SAAMA,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,gPAACD,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,IACe,IAAzCf,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"}
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","queue","this","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":"mSAAMA,eAQJ,WAAA,SAAAA,EAAYC,QAPJC,WAAK,EAAAC,KACLF,mBAIDG,EAAAA,KAAAA,WAGL,EAAAD,KAAKD,MAAQ,GACbC,KAAKF,cAAgBA,EACrBE,KAAKC,MAAQ,CACf,CAAC,QAAAC,EAAAL,EAAAM,iBAAAD,EAMDE,QAAA,WAAO,IAAAC,EACLL,KAAA,OAAIA,KAAKM,YACPN,KAAKC,QACEM,QAAQC,WAER,IAAID,QAAQ,SAACC,GAAO,OAAKH,EAAKN,MAAMU,KAAKD,EAAQ,EAE5D,EAACN,EAEDQ,QAAA,WACE,IAAMC,EAAcX,KAAKD,MAAMa,QAE3BD,EAEFE,WAAWF,EAAa,GAGxBX,KAAKC,OAET,IAACJ,KAAA,CAAA,CAAAiB,IAAAC,aAAAA,IAvBD,WACE,OAAWf,KAACC,MAAQD,KAAKF,aAC3B,kPARA,GAgCIkB,EAAa,WAEbC,eAAS,WAQb,SAAAA,EAAYnB,QAAAA,IAAAA,IAAAA,EAAwB,GAACE,KAP7BkB,wBACApB,EAAAA,KAAAA,qBAONE,KAAKkB,mBAAqB,GAC1BlB,KAAKF,cAAgBA,CACvB,CAAC,IAAAqB,EAAAF,EAAAd,UA+GA,OA/GAgB,EAEOC,qBAAA,SAAqBN,GAC3B,YAD2BA,IAAAA,IAAAA,EAAuBE,GAC3CK,QAAQrB,KAAKkB,mBAAmBJ,GACzC,EAACK,EAEOG,qBAAA,SAAqBR,GAI3B,gBAJ2BA,IAAAA,EAAuBE,GAC7ChB,KAAKoB,qBAAqBN,KAC7Bd,KAAKkB,mBAAmBJ,GAAO,IAAIjB,EAAcG,KAAKF,qBAE5CoB,mBAAmBJ,EACjC,EAACK,EAMOI,KAAA,SAAKT,YAAAA,IAAAA,EAAuBE,GAEhChB,KAAKoB,qBAAqBN,IACe,IAAzCd,KAAKsB,qBAAqBR,GAAKb,cAEpBD,KAACkB,mBAAmBJ,EAEnC,EAACK,EASDb,WAAA,SAAWQ,GACT,gBADSA,IAAAA,EAAuBE,GACzBhB,KAAKsB,qBAAqBR,GAAKR,UACxC,EAACa,EAMDf,QAAA,SAAQU,GACN,gBADMA,IAAAA,EAAuBE,GAClBhB,KAACsB,qBAAqBR,GAAKV,SACxC,EAACe,EAMDT,QAAA,SAAQI,YAAAA,IAAAA,EAAuBE,GAC7BhB,KAAKsB,qBAAqBR,GAAKJ,UAC/BV,KAAKuB,KAAKT,EACZ,EAACK,EAODlB,MAAA,SAAMa,GACJ,YADIA,IAAAA,IAAAA,EAAuBE,GACvBhB,KAAKoB,qBAAqBN,GACrBd,KAAKsB,qBAAqBR,GAAKb,MAE/B,CAEX,EAACkB,EAODK,SAAA,SAASV,GACP,YADOA,IAAAA,IAAAA,EAAuBE,GACnBhB,KAACC,MAAMa,GAAO,CAC3B,EAACK,EAQKM,iBACJC,EACAZ,QAAAA,IAAAA,IAAAA,EAAuBE,GAAU,IAAAW,IAAAA,EAGzB3B,KAAI,OAAAO,QAAAC,gCADRD,QAAAC,QACImB,EAAKvB,QAAQU,IAAIc,uBAAArB,QAAAC,QACVkB,IAAI,4FADPG,CAAA,EAEXC,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,YAAAA,IAAAA,EAAuBE,GAAU,IAEjC,OAAIhB,KAAKM,WAAWQ,GAClBP,QAAAC,QADER,KACUyB,QAAQC,EAAIZ,IAExBP,QAAAC,QAAO,KAEX,CAAC,MAAAwB,GAAA,OAAAzB,QAAA0B,OAAAD,EAAA,CAAA,EAAAf,CAAA,CA1HY"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chriscdn/promise-semaphore",
3
- "version": "2.0.9",
3
+ "version": "2.0.10",
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>",
@@ -9,7 +9,7 @@
9
9
  "source": "./src/index.ts",
10
10
  "main": "./lib/promise-semaphore.cjs",
11
11
  "module": "./lib/promise-semaphore.module.js",
12
- "unpkg": "./lib/promise-semaphore.umd.js",
12
+ "__unpkg": "./lib/promise-semaphore.umd.js",
13
13
  "exports": {
14
14
  "types": "./lib/index.d.ts",
15
15
  "require": "./lib/promise-semaphore.cjs",
@@ -17,15 +17,13 @@
17
17
  },
18
18
  "types": "./lib/index.d.ts",
19
19
  "scripts": {
20
- "build": "rm -rf ./lib/ && microbundle",
20
+ "build": "rm -rf ./lib/ && microbundle --format modern,esm,cjs",
21
21
  "dev": "microbundle watch",
22
- "test": "jest"
22
+ "test": "vitest"
23
23
  },
24
24
  "devDependencies": {
25
- "@types/jest": "^29.5.11",
26
- "jest": "^29.7.0",
27
25
  "microbundle": "^0.15.1",
28
- "ts-jest": "^29.1.1"
26
+ "vitest": "^3.0.7"
29
27
  },
30
28
  "keywords": [
31
29
  "promise",
@@ -34,5 +32,6 @@
34
32
  "mutex",
35
33
  "async",
36
34
  "throttle"
37
- ]
35
+ ],
36
+ "dependencies": {}
38
37
  }
package/tsconfig.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "compilerOptions": {
3
+ "types": ["vitest/importMeta"]
4
+ }
5
+ }
package/jest.config.js DELETED
@@ -1,5 +0,0 @@
1
- /** @type {import('ts-jest').JestConfigWithTsJest} */
2
- export default {
3
- preset: "ts-jest",
4
- testEnvironment: "node",
5
- };
@@ -1,3 +0,0 @@
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(){function e(e){var t=function(e,t){if("object"!=typeof e||!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)}(e);return"symbol"==typeof t?t:String(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.count++,Promise.resolve()):new Promise(function(t){return e.queue.push(t)})},i.release=function(){var e=this.queue.shift();e?setTimeout(e,0):this.count--},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}),t}(),n="_default";/*#__PURE__*/
2
- return 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)}},e}()});
3
- //# sourceMappingURL=promise-semaphore.umd.js.map
@@ -1 +0,0 @@
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":"6gBAAMA,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,gPAACD,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,IACe,IAAzCf,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"}