@sapphire/async-queue 1.6.0-pr-589.aa473f9.0 → 1.6.0-pr-935.7da5c8bb
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/CHANGELOG.md +63 -0
- package/README.md +41 -5
- package/dist/{index.js → cjs/index.cjs} +15 -21
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/{index.d.ts → cjs/index.d.cts} +2 -2
- package/dist/esm/index.d.mts +55 -0
- package/dist/{index.mjs → esm/index.mjs} +14 -20
- package/dist/esm/index.mjs.map +1 -0
- package/dist/{index.global.js → iife/index.global.js} +14 -20
- package/dist/iife/index.global.js.map +1 -0
- package/package.json +28 -21
- package/dist/index.global.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,69 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
# [@sapphire/async-queue@1.5.4](https://github.com/sapphiredev/utilities/compare/@sapphire/async-queue@1.5.3...@sapphire/async-queue@1.5.4) - (2024-11-02)
|
|
6
|
+
|
|
7
|
+
## 🏠 Refactor
|
|
8
|
+
|
|
9
|
+
- Resolve several sonar issues ([ba915f9](https://github.com/sapphiredev/utilities/commit/ba915f93ce0907828ba17b2d5ae009631ceb860d)) ([#823](https://github.com/sapphiredev/utilities/pull/823) by @favna)
|
|
10
|
+
|
|
11
|
+
## 🐛 Bug Fixes
|
|
12
|
+
|
|
13
|
+
- Move browser imports ([100ffb0](https://github.com/sapphiredev/utilities/commit/100ffb0a2471bb9f74cc580d282d11059e1a0a68)) ([#826](https://github.com/sapphiredev/utilities/pull/826) by @kyranet)
|
|
14
|
+
|
|
15
|
+
# [@sapphire/async-queue@1.5.3](https://github.com/sapphiredev/utilities/compare/@sapphire/async-queue@1.5.2...@sapphire/async-queue@1.5.3) - (2024-07-23)
|
|
16
|
+
|
|
17
|
+
## 🐛 Bug Fixes
|
|
18
|
+
|
|
19
|
+
- **deps:** Update all non-major dependencies ([083376a](https://github.com/sapphiredev/utilities/commit/083376aac55094dbeddb5194e8a8f0d794b8cceb)) ([#763](https://github.com/sapphiredev/utilities/pull/763) by @renovate[bot])
|
|
20
|
+
- **deps:** Update all non-major dependencies ([e7fdc5d](https://github.com/sapphiredev/utilities/commit/e7fdc5db3632a7f90292ef3978898da32730343a)) ([#752](https://github.com/sapphiredev/utilities/pull/752) by @renovate[bot])
|
|
21
|
+
|
|
22
|
+
## 📝 Documentation
|
|
23
|
+
|
|
24
|
+
- Add usage example in README ([3815167](https://github.com/sapphiredev/utilities/commit/38151673cac048ccccf4fb00c3c9cc98bbb3c452)) ([#777](https://github.com/sapphiredev/utilities/pull/777) by @kyranet)
|
|
25
|
+
|
|
26
|
+
# [@sapphire/async-queue@1.5.2](https://github.com/sapphiredev/utilities/compare/@sapphire/async-queue@1.5.2...@sapphire/async-queue@1.5.2) - (2024-01-19)
|
|
27
|
+
|
|
28
|
+
## 🐛 Bug Fixes
|
|
29
|
+
|
|
30
|
+
- Fixed commonjs typings export mapping (#707) ([216ff02](https://github.com/sapphiredev/utilities/commit/216ff0260d63a9590357f9a5069f1ae2b34eaf5d))
|
|
31
|
+
|
|
32
|
+
# [@sapphire/async-queue@1.5.1](https://github.com/sapphiredev/utilities/compare/@sapphire/async-queue@1.5.1...@sapphire/async-queue@1.5.1) - (2023-12-04)
|
|
33
|
+
|
|
34
|
+
## 🏠 Refactor
|
|
35
|
+
|
|
36
|
+
- Split `@sapphire/time-utilities` into 4 sub-packages (#462) ([574299a](https://github.com/sapphiredev/utilities/commit/574299a99e658f6500a2a7efa587a0919b2d1313))
|
|
37
|
+
|
|
38
|
+
## 🐛 Bug Fixes
|
|
39
|
+
|
|
40
|
+
- **async-queue:** Properly split CJS, ESM and IIFE ([75f215c](https://github.com/sapphiredev/utilities/commit/75f215cd8b42b3c57a92f2fe01dff59b7edb02d6))
|
|
41
|
+
- Update export mapping for proper ESM/CJS split ([dd0cff8](https://github.com/sapphiredev/utilities/commit/dd0cff8e9b03a15812f25f7a1180501a92422629))
|
|
42
|
+
- **deps:** Update all non-major dependencies (#607) ([9cc8bd0](https://github.com/sapphiredev/utilities/commit/9cc8bd0d4b5d650deab2c913e6c3d713861bae28))
|
|
43
|
+
- **deps:** Update all non-major dependencies (#577) ([291dd67](https://github.com/sapphiredev/utilities/commit/291dd6783e57d8f075ce566218ba076ef6c4bbbd))
|
|
44
|
+
- **deps:** Update all non-major dependencies (#545) ([40ca040](https://github.com/sapphiredev/utilities/commit/40ca040a21d8a0949682051a3a974538183a400e))
|
|
45
|
+
- **deps:** Update all non-major dependencies (#544) ([cc78f17](https://github.com/sapphiredev/utilities/commit/cc78f17390c7f3db08af92bf46a5a70a9c11dd5f))
|
|
46
|
+
- **deps:** Update all non-major dependencies (#532) ([8033d1f](https://github.com/sapphiredev/utilities/commit/8033d1ff7a5a1974134c61f424f171cccb2915e1))
|
|
47
|
+
- **deps:** Update all non-major dependencies (#514) ([21b07d5](https://github.com/sapphiredev/utilities/commit/21b07d5db529a0d982647a60de98e46f36f1ac93))
|
|
48
|
+
- **deps:** Update all non-major dependencies (#505) ([6178296](https://github.com/sapphiredev/utilities/commit/617829649e1e4deeee02b14533b5377cd5bc1fb3))
|
|
49
|
+
- **deps:** Update all non-major dependencies (#466) ([dc08606](https://github.com/sapphiredev/utilities/commit/dc08606a97154e47c65536123ac5f8b1262f7bd2))
|
|
50
|
+
- **deps:** Update all non-major dependencies ([e20f299](https://github.com/sapphiredev/utilities/commit/e20f29906e83cee000aaba9c6827e3bec5173d28))
|
|
51
|
+
|
|
52
|
+
## 📝 Documentation
|
|
53
|
+
|
|
54
|
+
- Add @06000208 as a contributor ([fa3349e](https://github.com/sapphiredev/utilities/commit/fa3349e55ce4ad008785211dec7bf8e2b5d933df))
|
|
55
|
+
- Add @didinele as a contributor ([42ef7b6](https://github.com/sapphiredev/utilities/commit/42ef7b656c48fd0e720119db1d622c8bba2791e9))
|
|
56
|
+
- Add @goestav as a contributor ([0e56a92](https://github.com/sapphiredev/utilities/commit/0e56a92a4e2d0942bfa207f81a8cb03b32312034))
|
|
57
|
+
- Add @CitTheDev as a contributor ([34169ea](https://github.com/sapphiredev/utilities/commit/34169eae1dc0476ccf5a6c4f36e28602a204829e))
|
|
58
|
+
- Add @legendhimslef as a contributor ([059b6f1](https://github.com/sapphiredev/utilities/commit/059b6f1ab5362d46d58624d06c1aa39192b0716f))
|
|
59
|
+
- Add @r-priyam as a contributor ([fb278ba](https://github.com/sapphiredev/utilities/commit/fb278bacf627ec6fc88752eafeb12df5f3177a2c))
|
|
60
|
+
- Change name of @kyranet (#451) ([df4fdef](https://github.com/sapphiredev/utilities/commit/df4fdefce18659975a4ebc224723638507d02d35))
|
|
61
|
+
- Update @RealShadowNova as a contributor ([a869ba0](https://github.com/sapphiredev/utilities/commit/a869ba0abfad041610b9115187d426aebe671af6))
|
|
62
|
+
|
|
63
|
+
## 🧪 Testing
|
|
64
|
+
|
|
65
|
+
- Update vitest to coverage v8 ([a4bc6e4](https://github.com/sapphiredev/utilities/commit/a4bc6e4f24ea60143a150ecc76fda6484f172ab9))
|
|
66
|
+
- Cleanup tests ([aec1bb2](https://github.com/sapphiredev/utilities/commit/aec1bb290d0f3c00a1ae4f4c86302ebbb161d348))
|
|
67
|
+
|
|
5
68
|
# [@sapphire/async-queue@1.5.0](https://github.com/sapphiredev/utilities/compare/@sapphire/async-queue@1.4.0...@sapphire/async-queue@1.5.0) - (2022-08-16)
|
|
6
69
|
|
|
7
70
|
## 🐛 Bug Fixes
|
package/README.md
CHANGED
|
@@ -7,21 +7,24 @@
|
|
|
7
7
|
**Sequential asynchronous lock-based queue for promises.**
|
|
8
8
|
|
|
9
9
|
[](https://github.com/sapphiredev/utilities/blob/main/LICENSE.md)
|
|
10
|
-
[](https://codecov.io/gh/sapphiredev/utilities)
|
|
11
10
|
[](https://bundlephobia.com/result?p=@sapphire/async-queue)
|
|
12
11
|
[](https://www.npmjs.com/package/@sapphire/async-queue)
|
|
13
12
|
|
|
14
13
|
</div>
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
**Table of Contents**
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
- [Features](#features)
|
|
18
|
+
- [Installation](#installation)
|
|
19
|
+
- [Usage](#usage)
|
|
20
|
+
- [Buy us some doughnuts](#buy-us-some-doughnuts)
|
|
21
|
+
- [Contributors](#contributors)
|
|
19
22
|
|
|
20
23
|
## Features
|
|
21
24
|
|
|
22
25
|
- Written in TypeScript
|
|
23
26
|
- Bundled with esbuild so it can be used in NodeJS and browsers
|
|
24
|
-
- Offers CommonJS, ESM and UMD bundles
|
|
27
|
+
- Offers CommonJS, ESM, and UMD bundles
|
|
25
28
|
- Fully tested
|
|
26
29
|
|
|
27
30
|
## Installation
|
|
@@ -32,13 +35,46 @@ You can use the following command to install this package, or replace `npm insta
|
|
|
32
35
|
npm install @sapphire/async-queue
|
|
33
36
|
```
|
|
34
37
|
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
**Note**: While this section uses `require`, the imports match 1:1 with ESM imports. For example `const { AsyncQueue } = require('@sapphire/async-queue')` equals `import { AsyncQueue } from '@sapphire/async-queue'`.
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// Require the AsyncQueue class
|
|
44
|
+
const { AsyncQueue } = require('@sapphire/async-queue');
|
|
45
|
+
|
|
46
|
+
const queue = new AsyncQueue();
|
|
47
|
+
|
|
48
|
+
async function request(url, options) {
|
|
49
|
+
// Wait and lock the queue
|
|
50
|
+
await queue.wait();
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
// Perform the operation sequentially
|
|
54
|
+
return await fetch(url, options);
|
|
55
|
+
} finally {
|
|
56
|
+
// Unlock the next promise in the queue
|
|
57
|
+
queue.shift();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
request(someUrl1, someOptions1);
|
|
62
|
+
// Will call fetch() immediately
|
|
63
|
+
|
|
64
|
+
request(someUrl2, someOptions2);
|
|
65
|
+
// Will call fetch() after the first finished
|
|
66
|
+
|
|
67
|
+
request(someUrl3, someOptions3);
|
|
68
|
+
// Will call fetch() after the second finished
|
|
69
|
+
```
|
|
70
|
+
|
|
35
71
|
---
|
|
36
72
|
|
|
37
73
|
## Buy us some doughnuts
|
|
38
74
|
|
|
39
75
|
Sapphire Community is and always will be open source, even if we don't get donations. That being said, we know there are amazing people who may still want to donate just to show their appreciation. Thank you very much in advance!
|
|
40
76
|
|
|
41
|
-
We accept donations through Open Collective, Ko-fi, PayPal, Patreon and GitHub Sponsorships. You can use the buttons below to donate through your method of choice.
|
|
77
|
+
We accept donations through Open Collective, Ko-fi, PayPal, Patreon, and GitHub Sponsorships. You can use the buttons below to donate through your method of choice.
|
|
42
78
|
|
|
43
79
|
| Donate With | Address |
|
|
44
80
|
| :-------------: | :-------------------------------------------------: |
|
|
@@ -3,13 +3,10 @@
|
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5
5
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
6
|
-
var __publicField = (obj, key, value) =>
|
|
7
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
8
|
-
return value;
|
|
9
|
-
};
|
|
6
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
10
7
|
|
|
11
|
-
// src/lib/
|
|
12
|
-
var
|
|
8
|
+
// src/lib/_AsyncQueueEntry.ts
|
|
9
|
+
var _AsyncQueueEntry = class _AsyncQueueEntry {
|
|
13
10
|
constructor(queue) {
|
|
14
11
|
__publicField(this, "promise");
|
|
15
12
|
__publicField(this, "resolve");
|
|
@@ -24,13 +21,11 @@ var AsyncQueueEntry = class {
|
|
|
24
21
|
});
|
|
25
22
|
}
|
|
26
23
|
setSignal(signal) {
|
|
27
|
-
if (signal.aborted)
|
|
28
|
-
return this;
|
|
24
|
+
if (signal.aborted) return this;
|
|
29
25
|
this.signal = signal;
|
|
30
26
|
this.signalListener = () => {
|
|
31
27
|
const index = this.queue["promises"].indexOf(this);
|
|
32
|
-
if (index !== -1)
|
|
33
|
-
this.queue["promises"].splice(index, 1);
|
|
28
|
+
if (index !== -1) this.queue["promises"].splice(index, 1);
|
|
34
29
|
this.reject(new Error("Request aborted manually"));
|
|
35
30
|
};
|
|
36
31
|
this.signal.addEventListener("abort", this.signalListener);
|
|
@@ -54,10 +49,11 @@ var AsyncQueueEntry = class {
|
|
|
54
49
|
}
|
|
55
50
|
}
|
|
56
51
|
};
|
|
57
|
-
__name(
|
|
52
|
+
__name(_AsyncQueueEntry, "AsyncQueueEntry");
|
|
53
|
+
var AsyncQueueEntry = _AsyncQueueEntry;
|
|
58
54
|
|
|
59
55
|
// src/lib/AsyncQueue.ts
|
|
60
|
-
var
|
|
56
|
+
var _AsyncQueue = class _AsyncQueue {
|
|
61
57
|
constructor() {
|
|
62
58
|
/**
|
|
63
59
|
* The promises array
|
|
@@ -106,16 +102,14 @@ var AsyncQueue = class {
|
|
|
106
102
|
return Promise.resolve();
|
|
107
103
|
}
|
|
108
104
|
this.promises.push(entry);
|
|
109
|
-
if (options?.signal)
|
|
110
|
-
entry.setSignal(options.signal);
|
|
105
|
+
if (options?.signal) entry.setSignal(options.signal);
|
|
111
106
|
return entry.promise;
|
|
112
107
|
}
|
|
113
108
|
/**
|
|
114
109
|
* Unlocks the head lock and transfers the next lock (if any) to the head.
|
|
115
110
|
*/
|
|
116
111
|
shift() {
|
|
117
|
-
if (this.promises.length === 0)
|
|
118
|
-
return;
|
|
112
|
+
if (this.promises.length === 0) return;
|
|
119
113
|
if (this.promises.length === 1) {
|
|
120
114
|
this.promises.shift();
|
|
121
115
|
return;
|
|
@@ -128,16 +122,16 @@ var AsyncQueue = class {
|
|
|
128
122
|
* @note To avoid race conditions, this does **not** unlock the head lock.
|
|
129
123
|
*/
|
|
130
124
|
abortAll() {
|
|
131
|
-
if (this.queued === 0)
|
|
132
|
-
return;
|
|
125
|
+
if (this.queued === 0) return;
|
|
133
126
|
for (let i = 1; i < this.promises.length; ++i) {
|
|
134
127
|
this.promises[i].abort();
|
|
135
128
|
}
|
|
136
129
|
this.promises.length = 1;
|
|
137
130
|
}
|
|
138
131
|
};
|
|
139
|
-
__name(
|
|
132
|
+
__name(_AsyncQueue, "AsyncQueue");
|
|
133
|
+
var AsyncQueue = _AsyncQueue;
|
|
140
134
|
|
|
141
135
|
exports.AsyncQueue = AsyncQueue;
|
|
142
|
-
//# sourceMappingURL=
|
|
143
|
-
//# sourceMappingURL=index.
|
|
136
|
+
//# sourceMappingURL=index.cjs.map
|
|
137
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/_AsyncQueueEntry.ts","../../src/lib/AsyncQueue.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import type { AsyncQueue } from './AsyncQueue';\n\n/**\n * @internal\n */\nexport class AsyncQueueEntry {\n\tpublic readonly promise: Promise<void>;\n\tprivate resolve!: () => void;\n\tprivate reject!: (error: Error) => void;\n\tprivate readonly queue: AsyncQueue;\n\tprivate signal: PolyFillAbortSignal | null = null;\n\tprivate signalListener: (() => void) | null = null;\n\n\tpublic constructor(queue: AsyncQueue) {\n\t\tthis.queue = queue;\n\t\tthis.promise = new Promise((resolve, reject) => {\n\t\t\tthis.resolve = resolve;\n\t\t\tthis.reject = reject;\n\t\t});\n\t}\n\n\tpublic setSignal(signal: AbortSignal) {\n\t\tif (signal.aborted) return this;\n\n\t\tthis.signal = signal as PolyFillAbortSignal;\n\t\tthis.signalListener = () => {\n\t\t\tconst index = this.queue['promises'].indexOf(this);\n\t\t\tif (index !== -1) this.queue['promises'].splice(index, 1);\n\n\t\t\tthis.reject(new Error('Request aborted manually'));\n\t\t};\n\t\tthis.signal.addEventListener('abort', this.signalListener);\n\t\treturn this;\n\t}\n\n\tpublic use() {\n\t\tthis.dispose();\n\t\tthis.resolve();\n\t\treturn this;\n\t}\n\n\tpublic abort() {\n\t\tthis.dispose();\n\t\tthis.reject(new Error('Request aborted manually'));\n\t\treturn this;\n\t}\n\n\tprivate dispose() {\n\t\tif (this.signal) {\n\t\t\tthis.signal.removeEventListener('abort', this.signalListener!);\n\t\t\tthis.signal = null;\n\t\t\tthis.signalListener = null;\n\t\t}\n\t}\n}\n\ninterface PolyFillAbortSignal {\n\treadonly aborted: boolean;\n\taddEventListener(type: 'abort', listener: () => void): void;\n\tremoveEventListener(type: 'abort', listener: () => void): void;\n}\n","import { AsyncQueueEntry } from './_AsyncQueueEntry';\n\n/**\n * The AsyncQueue class used to sequentialize burst requests\n */\nexport class AsyncQueue {\n\t/**\n\t * The amount of entries in the queue, including the head.\n\t * @seealso {@link queued} for the queued count.\n\t */\n\tpublic get remaining(): number {\n\t\treturn this.promises.length;\n\t}\n\n\t/**\n\t * The amount of queued entries.\n\t * @seealso {@link remaining} for the count with the head.\n\t */\n\tpublic get queued(): number {\n\t\treturn this.remaining === 0 ? 0 : this.remaining - 1;\n\t}\n\n\t/**\n\t * The promises array\n\t */\n\tprivate readonly promises: AsyncQueueEntry[] = [];\n\n\t/**\n\t * Waits for last promise and queues a new one\n\t * @example\n\t * ```typescript\n\t * const queue = new AsyncQueue();\n\t * async function request(url, options) {\n\t * await queue.wait({ signal: options.signal });\n\t * try {\n\t * const result = await fetch(url, options);\n\t * // Do some operations with 'result'\n\t * } finally {\n\t * // Remove first entry from the queue and resolve for the next entry\n\t * queue.shift();\n\t * }\n\t * }\n\t *\n\t * request(someUrl1, someOptions1); // Will call fetch() immediately\n\t * request(someUrl2, someOptions2); // Will call fetch() after the first finished\n\t * request(someUrl3, someOptions3); // Will call fetch() after the second finished\n\t * ```\n\t */\n\tpublic wait(options?: Readonly<AsyncQueueWaitOptions>): Promise<void> {\n\t\tconst entry = new AsyncQueueEntry(this);\n\n\t\tif (this.promises.length === 0) {\n\t\t\tthis.promises.push(entry);\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tthis.promises.push(entry);\n\t\tif (options?.signal) entry.setSignal(options.signal);\n\t\treturn entry.promise;\n\t}\n\n\t/**\n\t * Unlocks the head lock and transfers the next lock (if any) to the head.\n\t */\n\tpublic shift(): void {\n\t\tif (this.promises.length === 0) return;\n\t\tif (this.promises.length === 1) {\n\t\t\t// Remove the head entry.\n\t\t\tthis.promises.shift();\n\t\t\treturn;\n\t\t}\n\n\t\t// Remove the head entry, making the 2nd entry the new one.\n\t\t// Then use the head entry, which will unlock the promise.\n\t\tthis.promises.shift();\n\t\tthis.promises[0].use();\n\t}\n\n\t/**\n\t * Aborts all the pending promises.\n\t * @note To avoid race conditions, this does **not** unlock the head lock.\n\t */\n\tpublic abortAll(): void {\n\t\t// If there are no queued entries, skip early.\n\t\tif (this.queued === 0) return;\n\n\t\t// Abort all the entries except the head, that is why the loop starts at\n\t\t// 1 and not at 0.\n\t\tfor (let i = 1; i < this.promises.length; ++i) {\n\t\t\tthis.promises[i].abort();\n\t\t}\n\n\t\tthis.promises.length = 1;\n\t}\n}\n\nexport interface AsyncQueueWaitOptions {\n\tsignal?: AbortSignal | undefined | null;\n}\n"]}
|
|
@@ -15,7 +15,7 @@ declare class AsyncQueue {
|
|
|
15
15
|
/**
|
|
16
16
|
* The promises array
|
|
17
17
|
*/
|
|
18
|
-
private promises;
|
|
18
|
+
private readonly promises;
|
|
19
19
|
/**
|
|
20
20
|
* Waits for last promise and queues a new one
|
|
21
21
|
* @example
|
|
@@ -52,4 +52,4 @@ interface AsyncQueueWaitOptions {
|
|
|
52
52
|
signal?: AbortSignal | undefined | null;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
export { AsyncQueue, AsyncQueueWaitOptions };
|
|
55
|
+
export { AsyncQueue, type AsyncQueueWaitOptions };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The AsyncQueue class used to sequentialize burst requests
|
|
3
|
+
*/
|
|
4
|
+
declare class AsyncQueue {
|
|
5
|
+
/**
|
|
6
|
+
* The amount of entries in the queue, including the head.
|
|
7
|
+
* @seealso {@link queued} for the queued count.
|
|
8
|
+
*/
|
|
9
|
+
get remaining(): number;
|
|
10
|
+
/**
|
|
11
|
+
* The amount of queued entries.
|
|
12
|
+
* @seealso {@link remaining} for the count with the head.
|
|
13
|
+
*/
|
|
14
|
+
get queued(): number;
|
|
15
|
+
/**
|
|
16
|
+
* The promises array
|
|
17
|
+
*/
|
|
18
|
+
private readonly promises;
|
|
19
|
+
/**
|
|
20
|
+
* Waits for last promise and queues a new one
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const queue = new AsyncQueue();
|
|
24
|
+
* async function request(url, options) {
|
|
25
|
+
* await queue.wait({ signal: options.signal });
|
|
26
|
+
* try {
|
|
27
|
+
* const result = await fetch(url, options);
|
|
28
|
+
* // Do some operations with 'result'
|
|
29
|
+
* } finally {
|
|
30
|
+
* // Remove first entry from the queue and resolve for the next entry
|
|
31
|
+
* queue.shift();
|
|
32
|
+
* }
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* request(someUrl1, someOptions1); // Will call fetch() immediately
|
|
36
|
+
* request(someUrl2, someOptions2); // Will call fetch() after the first finished
|
|
37
|
+
* request(someUrl3, someOptions3); // Will call fetch() after the second finished
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
wait(options?: Readonly<AsyncQueueWaitOptions>): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Unlocks the head lock and transfers the next lock (if any) to the head.
|
|
43
|
+
*/
|
|
44
|
+
shift(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Aborts all the pending promises.
|
|
47
|
+
* @note To avoid race conditions, this does **not** unlock the head lock.
|
|
48
|
+
*/
|
|
49
|
+
abortAll(): void;
|
|
50
|
+
}
|
|
51
|
+
interface AsyncQueueWaitOptions {
|
|
52
|
+
signal?: AbortSignal | undefined | null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export { AsyncQueue, type AsyncQueueWaitOptions };
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
4
|
-
var __publicField = (obj, key, value) =>
|
|
5
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
|
-
return value;
|
|
7
|
-
};
|
|
4
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
8
5
|
|
|
9
|
-
// src/lib/
|
|
10
|
-
var
|
|
6
|
+
// src/lib/_AsyncQueueEntry.ts
|
|
7
|
+
var _AsyncQueueEntry = class _AsyncQueueEntry {
|
|
11
8
|
constructor(queue) {
|
|
12
9
|
__publicField(this, "promise");
|
|
13
10
|
__publicField(this, "resolve");
|
|
@@ -22,13 +19,11 @@ var AsyncQueueEntry = class {
|
|
|
22
19
|
});
|
|
23
20
|
}
|
|
24
21
|
setSignal(signal) {
|
|
25
|
-
if (signal.aborted)
|
|
26
|
-
return this;
|
|
22
|
+
if (signal.aborted) return this;
|
|
27
23
|
this.signal = signal;
|
|
28
24
|
this.signalListener = () => {
|
|
29
25
|
const index = this.queue["promises"].indexOf(this);
|
|
30
|
-
if (index !== -1)
|
|
31
|
-
this.queue["promises"].splice(index, 1);
|
|
26
|
+
if (index !== -1) this.queue["promises"].splice(index, 1);
|
|
32
27
|
this.reject(new Error("Request aborted manually"));
|
|
33
28
|
};
|
|
34
29
|
this.signal.addEventListener("abort", this.signalListener);
|
|
@@ -52,10 +47,11 @@ var AsyncQueueEntry = class {
|
|
|
52
47
|
}
|
|
53
48
|
}
|
|
54
49
|
};
|
|
55
|
-
__name(
|
|
50
|
+
__name(_AsyncQueueEntry, "AsyncQueueEntry");
|
|
51
|
+
var AsyncQueueEntry = _AsyncQueueEntry;
|
|
56
52
|
|
|
57
53
|
// src/lib/AsyncQueue.ts
|
|
58
|
-
var
|
|
54
|
+
var _AsyncQueue = class _AsyncQueue {
|
|
59
55
|
constructor() {
|
|
60
56
|
/**
|
|
61
57
|
* The promises array
|
|
@@ -104,16 +100,14 @@ var AsyncQueue = class {
|
|
|
104
100
|
return Promise.resolve();
|
|
105
101
|
}
|
|
106
102
|
this.promises.push(entry);
|
|
107
|
-
if (options?.signal)
|
|
108
|
-
entry.setSignal(options.signal);
|
|
103
|
+
if (options?.signal) entry.setSignal(options.signal);
|
|
109
104
|
return entry.promise;
|
|
110
105
|
}
|
|
111
106
|
/**
|
|
112
107
|
* Unlocks the head lock and transfers the next lock (if any) to the head.
|
|
113
108
|
*/
|
|
114
109
|
shift() {
|
|
115
|
-
if (this.promises.length === 0)
|
|
116
|
-
return;
|
|
110
|
+
if (this.promises.length === 0) return;
|
|
117
111
|
if (this.promises.length === 1) {
|
|
118
112
|
this.promises.shift();
|
|
119
113
|
return;
|
|
@@ -126,16 +120,16 @@ var AsyncQueue = class {
|
|
|
126
120
|
* @note To avoid race conditions, this does **not** unlock the head lock.
|
|
127
121
|
*/
|
|
128
122
|
abortAll() {
|
|
129
|
-
if (this.queued === 0)
|
|
130
|
-
return;
|
|
123
|
+
if (this.queued === 0) return;
|
|
131
124
|
for (let i = 1; i < this.promises.length; ++i) {
|
|
132
125
|
this.promises[i].abort();
|
|
133
126
|
}
|
|
134
127
|
this.promises.length = 1;
|
|
135
128
|
}
|
|
136
129
|
};
|
|
137
|
-
__name(
|
|
130
|
+
__name(_AsyncQueue, "AsyncQueue");
|
|
131
|
+
var AsyncQueue = _AsyncQueue;
|
|
138
132
|
|
|
139
133
|
export { AsyncQueue };
|
|
140
|
-
//# sourceMappingURL=
|
|
134
|
+
//# sourceMappingURL=index.mjs.map
|
|
141
135
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/_AsyncQueueEntry.ts","../../src/lib/AsyncQueue.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { AsyncQueue } from './AsyncQueue';\n\n/**\n * @internal\n */\nexport class AsyncQueueEntry {\n\tpublic readonly promise: Promise<void>;\n\tprivate resolve!: () => void;\n\tprivate reject!: (error: Error) => void;\n\tprivate readonly queue: AsyncQueue;\n\tprivate signal: PolyFillAbortSignal | null = null;\n\tprivate signalListener: (() => void) | null = null;\n\n\tpublic constructor(queue: AsyncQueue) {\n\t\tthis.queue = queue;\n\t\tthis.promise = new Promise((resolve, reject) => {\n\t\t\tthis.resolve = resolve;\n\t\t\tthis.reject = reject;\n\t\t});\n\t}\n\n\tpublic setSignal(signal: AbortSignal) {\n\t\tif (signal.aborted) return this;\n\n\t\tthis.signal = signal as PolyFillAbortSignal;\n\t\tthis.signalListener = () => {\n\t\t\tconst index = this.queue['promises'].indexOf(this);\n\t\t\tif (index !== -1) this.queue['promises'].splice(index, 1);\n\n\t\t\tthis.reject(new Error('Request aborted manually'));\n\t\t};\n\t\tthis.signal.addEventListener('abort', this.signalListener);\n\t\treturn this;\n\t}\n\n\tpublic use() {\n\t\tthis.dispose();\n\t\tthis.resolve();\n\t\treturn this;\n\t}\n\n\tpublic abort() {\n\t\tthis.dispose();\n\t\tthis.reject(new Error('Request aborted manually'));\n\t\treturn this;\n\t}\n\n\tprivate dispose() {\n\t\tif (this.signal) {\n\t\t\tthis.signal.removeEventListener('abort', this.signalListener!);\n\t\t\tthis.signal = null;\n\t\t\tthis.signalListener = null;\n\t\t}\n\t}\n}\n\ninterface PolyFillAbortSignal {\n\treadonly aborted: boolean;\n\taddEventListener(type: 'abort', listener: () => void): void;\n\tremoveEventListener(type: 'abort', listener: () => void): void;\n}\n","import { AsyncQueueEntry } from './_AsyncQueueEntry';\n\n/**\n * The AsyncQueue class used to sequentialize burst requests\n */\nexport class AsyncQueue {\n\t/**\n\t * The amount of entries in the queue, including the head.\n\t * @seealso {@link queued} for the queued count.\n\t */\n\tpublic get remaining(): number {\n\t\treturn this.promises.length;\n\t}\n\n\t/**\n\t * The amount of queued entries.\n\t * @seealso {@link remaining} for the count with the head.\n\t */\n\tpublic get queued(): number {\n\t\treturn this.remaining === 0 ? 0 : this.remaining - 1;\n\t}\n\n\t/**\n\t * The promises array\n\t */\n\tprivate readonly promises: AsyncQueueEntry[] = [];\n\n\t/**\n\t * Waits for last promise and queues a new one\n\t * @example\n\t * ```typescript\n\t * const queue = new AsyncQueue();\n\t * async function request(url, options) {\n\t * await queue.wait({ signal: options.signal });\n\t * try {\n\t * const result = await fetch(url, options);\n\t * // Do some operations with 'result'\n\t * } finally {\n\t * // Remove first entry from the queue and resolve for the next entry\n\t * queue.shift();\n\t * }\n\t * }\n\t *\n\t * request(someUrl1, someOptions1); // Will call fetch() immediately\n\t * request(someUrl2, someOptions2); // Will call fetch() after the first finished\n\t * request(someUrl3, someOptions3); // Will call fetch() after the second finished\n\t * ```\n\t */\n\tpublic wait(options?: Readonly<AsyncQueueWaitOptions>): Promise<void> {\n\t\tconst entry = new AsyncQueueEntry(this);\n\n\t\tif (this.promises.length === 0) {\n\t\t\tthis.promises.push(entry);\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tthis.promises.push(entry);\n\t\tif (options?.signal) entry.setSignal(options.signal);\n\t\treturn entry.promise;\n\t}\n\n\t/**\n\t * Unlocks the head lock and transfers the next lock (if any) to the head.\n\t */\n\tpublic shift(): void {\n\t\tif (this.promises.length === 0) return;\n\t\tif (this.promises.length === 1) {\n\t\t\t// Remove the head entry.\n\t\t\tthis.promises.shift();\n\t\t\treturn;\n\t\t}\n\n\t\t// Remove the head entry, making the 2nd entry the new one.\n\t\t// Then use the head entry, which will unlock the promise.\n\t\tthis.promises.shift();\n\t\tthis.promises[0].use();\n\t}\n\n\t/**\n\t * Aborts all the pending promises.\n\t * @note To avoid race conditions, this does **not** unlock the head lock.\n\t */\n\tpublic abortAll(): void {\n\t\t// If there are no queued entries, skip early.\n\t\tif (this.queued === 0) return;\n\n\t\t// Abort all the entries except the head, that is why the loop starts at\n\t\t// 1 and not at 0.\n\t\tfor (let i = 1; i < this.promises.length; ++i) {\n\t\t\tthis.promises[i].abort();\n\t\t}\n\n\t\tthis.promises.length = 1;\n\t}\n}\n\nexport interface AsyncQueueWaitOptions {\n\tsignal?: AbortSignal | undefined | null;\n}\n"]}
|
|
@@ -4,13 +4,10 @@ var SapphireAsyncQueue = (function (exports) {
|
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
6
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
|
-
var __publicField = (obj, key, value) =>
|
|
8
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
9
|
-
return value;
|
|
10
|
-
};
|
|
7
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
11
8
|
|
|
12
|
-
// src/lib/
|
|
13
|
-
var
|
|
9
|
+
// src/lib/_AsyncQueueEntry.ts
|
|
10
|
+
var _AsyncQueueEntry = class _AsyncQueueEntry {
|
|
14
11
|
constructor(queue) {
|
|
15
12
|
__publicField(this, "promise");
|
|
16
13
|
__publicField(this, "resolve");
|
|
@@ -25,13 +22,11 @@ var SapphireAsyncQueue = (function (exports) {
|
|
|
25
22
|
});
|
|
26
23
|
}
|
|
27
24
|
setSignal(signal) {
|
|
28
|
-
if (signal.aborted)
|
|
29
|
-
return this;
|
|
25
|
+
if (signal.aborted) return this;
|
|
30
26
|
this.signal = signal;
|
|
31
27
|
this.signalListener = () => {
|
|
32
28
|
const index = this.queue["promises"].indexOf(this);
|
|
33
|
-
if (index !== -1)
|
|
34
|
-
this.queue["promises"].splice(index, 1);
|
|
29
|
+
if (index !== -1) this.queue["promises"].splice(index, 1);
|
|
35
30
|
this.reject(new Error("Request aborted manually"));
|
|
36
31
|
};
|
|
37
32
|
this.signal.addEventListener("abort", this.signalListener);
|
|
@@ -55,10 +50,11 @@ var SapphireAsyncQueue = (function (exports) {
|
|
|
55
50
|
}
|
|
56
51
|
}
|
|
57
52
|
};
|
|
58
|
-
__name(
|
|
53
|
+
__name(_AsyncQueueEntry, "AsyncQueueEntry");
|
|
54
|
+
var AsyncQueueEntry = _AsyncQueueEntry;
|
|
59
55
|
|
|
60
56
|
// src/lib/AsyncQueue.ts
|
|
61
|
-
var
|
|
57
|
+
var _AsyncQueue = class _AsyncQueue {
|
|
62
58
|
constructor() {
|
|
63
59
|
/**
|
|
64
60
|
* The promises array
|
|
@@ -107,16 +103,14 @@ var SapphireAsyncQueue = (function (exports) {
|
|
|
107
103
|
return Promise.resolve();
|
|
108
104
|
}
|
|
109
105
|
this.promises.push(entry);
|
|
110
|
-
if (options?.signal)
|
|
111
|
-
entry.setSignal(options.signal);
|
|
106
|
+
if (options?.signal) entry.setSignal(options.signal);
|
|
112
107
|
return entry.promise;
|
|
113
108
|
}
|
|
114
109
|
/**
|
|
115
110
|
* Unlocks the head lock and transfers the next lock (if any) to the head.
|
|
116
111
|
*/
|
|
117
112
|
shift() {
|
|
118
|
-
if (this.promises.length === 0)
|
|
119
|
-
return;
|
|
113
|
+
if (this.promises.length === 0) return;
|
|
120
114
|
if (this.promises.length === 1) {
|
|
121
115
|
this.promises.shift();
|
|
122
116
|
return;
|
|
@@ -129,20 +123,20 @@ var SapphireAsyncQueue = (function (exports) {
|
|
|
129
123
|
* @note To avoid race conditions, this does **not** unlock the head lock.
|
|
130
124
|
*/
|
|
131
125
|
abortAll() {
|
|
132
|
-
if (this.queued === 0)
|
|
133
|
-
return;
|
|
126
|
+
if (this.queued === 0) return;
|
|
134
127
|
for (let i = 1; i < this.promises.length; ++i) {
|
|
135
128
|
this.promises[i].abort();
|
|
136
129
|
}
|
|
137
130
|
this.promises.length = 1;
|
|
138
131
|
}
|
|
139
132
|
};
|
|
140
|
-
__name(
|
|
133
|
+
__name(_AsyncQueue, "AsyncQueue");
|
|
134
|
+
var AsyncQueue = _AsyncQueue;
|
|
141
135
|
|
|
142
136
|
exports.AsyncQueue = AsyncQueue;
|
|
143
137
|
|
|
144
138
|
return exports;
|
|
145
139
|
|
|
146
140
|
})({});
|
|
147
|
-
//# sourceMappingURL=
|
|
141
|
+
//# sourceMappingURL=index.global.js.map
|
|
148
142
|
//# sourceMappingURL=index.global.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/_AsyncQueueEntry.ts","../../src/lib/AsyncQueue.ts"],"names":[],"mappings":";;;;;;;;;EAKO,IAAM,gBAAA,GAAN,MAAM,gBAAA,CAAgB;EAAA,EAQrB,YAAY,KAAA,EAAmB;EAPtC,IAAA,aAAA,CAAA,IAAA,EAAgB,SAAA,CAAA;EAChB,IAAA,aAAA,CAAA,IAAA,EAAQ,SAAA,CAAA;EACR,IAAA,aAAA,CAAA,IAAA,EAAQ,QAAA,CAAA;EACR,IAAA,aAAA,CAAA,IAAA,EAAiB,OAAA,CAAA;EACjB,IAAA,aAAA,CAAA,IAAA,EAAQ,QAAA,EAAqC,IAAA,CAAA;EAC7C,IAAA,aAAA,CAAA,IAAA,EAAQ,gBAAA,EAAsC,IAAA,CAAA;EAG7C,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;EACb,IAAA,IAAA,CAAK,OAAA,GAAU,IAAI,OAAA,CAAQ,CAAC,SAAS,MAAA,KAAW;EAC/C,MAAA,IAAA,CAAK,OAAA,GAAU,OAAA;EACf,MAAA,IAAA,CAAK,MAAA,GAAS,MAAA;EAAA,IACf,CAAC,CAAA;EAAA,EACF;EAAA,EAEO,UAAU,MAAA,EAAqB;EACrC,IAAA,IAAI,MAAA,CAAO,SAAS,OAAO,IAAA;EAE3B,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;EACd,IAAA,IAAA,CAAK,iBAAiB,MAAM;EAC3B,MAAA,MAAM,QAAQ,IAAA,CAAK,KAAA,CAAM,UAAU,CAAA,CAAE,QAAQ,IAAI,CAAA;EACjD,MAAA,IAAI,KAAA,KAAU,IAAI,IAAA,CAAK,KAAA,CAAM,UAAU,CAAA,CAAE,MAAA,CAAO,OAAO,CAAC,CAAA;EAExD,MAAA,IAAA,CAAK,MAAA,CAAO,IAAI,KAAA,CAAM,0BAA0B,CAAC,CAAA;EAAA,IAClD,CAAA;EACA,IAAA,IAAA,CAAK,MAAA,CAAO,gBAAA,CAAiB,OAAA,EAAS,IAAA,CAAK,cAAc,CAAA;EACzD,IAAA,OAAO,IAAA;EAAA,EACR;EAAA,EAEO,GAAA,GAAM;EACZ,IAAA,IAAA,CAAK,OAAA,EAAQ;EACb,IAAA,IAAA,CAAK,OAAA,EAAQ;EACb,IAAA,OAAO,IAAA;EAAA,EACR;EAAA,EAEO,KAAA,GAAQ;EACd,IAAA,IAAA,CAAK,OAAA,EAAQ;EACb,IAAA,IAAA,CAAK,MAAA,CAAO,IAAI,KAAA,CAAM,0BAA0B,CAAC,CAAA;EACjD,IAAA,OAAO,IAAA;EAAA,EACR;EAAA,EAEQ,OAAA,GAAU;EACjB,IAAA,IAAI,KAAK,MAAA,EAAQ;EAChB,MAAA,IAAA,CAAK,MAAA,CAAO,mBAAA,CAAoB,OAAA,EAAS,IAAA,CAAK,cAAe,CAAA;EAC7D,MAAA,IAAA,CAAK,MAAA,GAAS,IAAA;EACd,MAAA,IAAA,CAAK,cAAA,GAAiB,IAAA;EAAA,IACvB;EAAA,EACD;EACD,CAAA;EAjD6B,MAAA,CAAA,gBAAA,EAAA,iBAAA,CAAA;EAAtB,IAAM,eAAA,GAAN,gBAAA;;;ECAA,IAAM,WAAA,GAAN,MAAM,WAAA,CAAW;EAAA,EAAjB,WAAA,GAAA;EAoBN;EAAA;EAAA;EAAA,IAAA,aAAA,CAAA,IAAA,EAAiB,YAA8B,EAAC,CAAA;EAAA,EAAA;EAAA;EAAA;EAAA;EAAA;EAAA,EAfhD,IAAW,SAAA,GAAoB;EAC9B,IAAA,OAAO,KAAK,QAAA,CAAS,MAAA;EAAA,EACtB;EAAA;EAAA;EAAA;EAAA;EAAA,EAMA,IAAW,MAAA,GAAiB;EAC3B,IAAA,OAAO,IAAA,CAAK,SAAA,KAAc,CAAA,GAAI,CAAA,GAAI,KAAK,SAAA,GAAY,CAAA;EAAA,EACpD;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA;EAAA,EA4BO,KAAK,OAAA,EAA0D;EACrE,IAAA,MAAM,KAAA,GAAQ,IAAI,eAAA,CAAgB,IAAI,CAAA;EAEtC,IAAA,IAAI,IAAA,CAAK,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG;EAC/B,MAAA,IAAA,CAAK,QAAA,CAAS,KAAK,KAAK,CAAA;EACxB,MAAA,OAAO,QAAQ,OAAA,EAAQ;EAAA,IACxB;EAEA,IAAA,IAAA,CAAK,QAAA,CAAS,KAAK,KAAK,CAAA;EACxB,IAAA,IAAI,OAAA,EAAS,MAAA,EAAQ,KAAA,CAAM,SAAA,CAAU,QAAQ,MAAM,CAAA;EACnD,IAAA,OAAO,KAAA,CAAM,OAAA;EAAA,EACd;EAAA;EAAA;EAAA;EAAA,EAKO,KAAA,GAAc;EACpB,IAAA,IAAI,IAAA,CAAK,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG;EAChC,IAAA,IAAI,IAAA,CAAK,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG;EAE/B,MAAA,IAAA,CAAK,SAAS,KAAA,EAAM;EACpB,MAAA;EAAA,IACD;EAIA,IAAA,IAAA,CAAK,SAAS,KAAA,EAAM;EACpB,IAAA,IAAA,CAAK,QAAA,CAAS,CAAC,CAAA,CAAE,GAAA,EAAI;EAAA,EACtB;EAAA;EAAA;EAAA;EAAA;EAAA,EAMO,QAAA,GAAiB;EAEvB,IAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;EAIvB,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,KAAK,QAAA,CAAS,MAAA,EAAQ,EAAE,CAAA,EAAG;EAC9C,MAAA,IAAA,CAAK,QAAA,CAAS,CAAC,CAAA,CAAE,KAAA,EAAM;EAAA,IACxB;EAEA,IAAA,IAAA,CAAK,SAAS,MAAA,GAAS,CAAA;EAAA,EACxB;EACD,CAAA;EAzFwB,MAAA,CAAA,WAAA,EAAA,YAAA,CAAA;AAAjB,MAAM,UAAA,GAAN","file":"index.global.js","sourcesContent":["import type { AsyncQueue } from './AsyncQueue';\n\n/**\n * @internal\n */\nexport class AsyncQueueEntry {\n\tpublic readonly promise: Promise<void>;\n\tprivate resolve!: () => void;\n\tprivate reject!: (error: Error) => void;\n\tprivate readonly queue: AsyncQueue;\n\tprivate signal: PolyFillAbortSignal | null = null;\n\tprivate signalListener: (() => void) | null = null;\n\n\tpublic constructor(queue: AsyncQueue) {\n\t\tthis.queue = queue;\n\t\tthis.promise = new Promise((resolve, reject) => {\n\t\t\tthis.resolve = resolve;\n\t\t\tthis.reject = reject;\n\t\t});\n\t}\n\n\tpublic setSignal(signal: AbortSignal) {\n\t\tif (signal.aborted) return this;\n\n\t\tthis.signal = signal as PolyFillAbortSignal;\n\t\tthis.signalListener = () => {\n\t\t\tconst index = this.queue['promises'].indexOf(this);\n\t\t\tif (index !== -1) this.queue['promises'].splice(index, 1);\n\n\t\t\tthis.reject(new Error('Request aborted manually'));\n\t\t};\n\t\tthis.signal.addEventListener('abort', this.signalListener);\n\t\treturn this;\n\t}\n\n\tpublic use() {\n\t\tthis.dispose();\n\t\tthis.resolve();\n\t\treturn this;\n\t}\n\n\tpublic abort() {\n\t\tthis.dispose();\n\t\tthis.reject(new Error('Request aborted manually'));\n\t\treturn this;\n\t}\n\n\tprivate dispose() {\n\t\tif (this.signal) {\n\t\t\tthis.signal.removeEventListener('abort', this.signalListener!);\n\t\t\tthis.signal = null;\n\t\t\tthis.signalListener = null;\n\t\t}\n\t}\n}\n\ninterface PolyFillAbortSignal {\n\treadonly aborted: boolean;\n\taddEventListener(type: 'abort', listener: () => void): void;\n\tremoveEventListener(type: 'abort', listener: () => void): void;\n}\n","import { AsyncQueueEntry } from './_AsyncQueueEntry';\n\n/**\n * The AsyncQueue class used to sequentialize burst requests\n */\nexport class AsyncQueue {\n\t/**\n\t * The amount of entries in the queue, including the head.\n\t * @seealso {@link queued} for the queued count.\n\t */\n\tpublic get remaining(): number {\n\t\treturn this.promises.length;\n\t}\n\n\t/**\n\t * The amount of queued entries.\n\t * @seealso {@link remaining} for the count with the head.\n\t */\n\tpublic get queued(): number {\n\t\treturn this.remaining === 0 ? 0 : this.remaining - 1;\n\t}\n\n\t/**\n\t * The promises array\n\t */\n\tprivate readonly promises: AsyncQueueEntry[] = [];\n\n\t/**\n\t * Waits for last promise and queues a new one\n\t * @example\n\t * ```typescript\n\t * const queue = new AsyncQueue();\n\t * async function request(url, options) {\n\t * await queue.wait({ signal: options.signal });\n\t * try {\n\t * const result = await fetch(url, options);\n\t * // Do some operations with 'result'\n\t * } finally {\n\t * // Remove first entry from the queue and resolve for the next entry\n\t * queue.shift();\n\t * }\n\t * }\n\t *\n\t * request(someUrl1, someOptions1); // Will call fetch() immediately\n\t * request(someUrl2, someOptions2); // Will call fetch() after the first finished\n\t * request(someUrl3, someOptions3); // Will call fetch() after the second finished\n\t * ```\n\t */\n\tpublic wait(options?: Readonly<AsyncQueueWaitOptions>): Promise<void> {\n\t\tconst entry = new AsyncQueueEntry(this);\n\n\t\tif (this.promises.length === 0) {\n\t\t\tthis.promises.push(entry);\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tthis.promises.push(entry);\n\t\tif (options?.signal) entry.setSignal(options.signal);\n\t\treturn entry.promise;\n\t}\n\n\t/**\n\t * Unlocks the head lock and transfers the next lock (if any) to the head.\n\t */\n\tpublic shift(): void {\n\t\tif (this.promises.length === 0) return;\n\t\tif (this.promises.length === 1) {\n\t\t\t// Remove the head entry.\n\t\t\tthis.promises.shift();\n\t\t\treturn;\n\t\t}\n\n\t\t// Remove the head entry, making the 2nd entry the new one.\n\t\t// Then use the head entry, which will unlock the promise.\n\t\tthis.promises.shift();\n\t\tthis.promises[0].use();\n\t}\n\n\t/**\n\t * Aborts all the pending promises.\n\t * @note To avoid race conditions, this does **not** unlock the head lock.\n\t */\n\tpublic abortAll(): void {\n\t\t// If there are no queued entries, skip early.\n\t\tif (this.queued === 0) return;\n\n\t\t// Abort all the entries except the head, that is why the loop starts at\n\t\t// 1 and not at 0.\n\t\tfor (let i = 1; i < this.promises.length; ++i) {\n\t\t\tthis.promises[i].abort();\n\t\t}\n\n\t\tthis.promises.length = 1;\n\t}\n}\n\nexport interface AsyncQueueWaitOptions {\n\tsignal?: AbortSignal | undefined | null;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sapphire/async-queue",
|
|
3
|
-
"version": "1.6.0-pr-
|
|
3
|
+
"version": "1.6.0-pr-935.7da5c8bb",
|
|
4
4
|
"description": "Sequential asynchronous lock-based queue for promises",
|
|
5
5
|
"author": "@sapphire",
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"main": "dist/index.
|
|
8
|
-
"module": "dist/index.mjs",
|
|
9
|
-
"browser": "dist/index.global.js",
|
|
10
|
-
"unpkg": "dist/index.global.js",
|
|
11
|
-
"types": "dist/index.d.
|
|
7
|
+
"main": "dist/cjs/index.cjs",
|
|
8
|
+
"module": "dist/esm/index.mjs",
|
|
9
|
+
"browser": "dist/iife/index.global.js",
|
|
10
|
+
"unpkg": "dist/iife/index.global.js",
|
|
11
|
+
"types": "dist/cjs/index.d.cts",
|
|
12
12
|
"exports": {
|
|
13
|
-
"import":
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
"import": {
|
|
14
|
+
"types": "./dist/esm/index.d.mts",
|
|
15
|
+
"default": "./dist/esm/index.mjs"
|
|
16
|
+
},
|
|
17
|
+
"require": {
|
|
18
|
+
"types": "./dist/cjs/index.d.cts",
|
|
19
|
+
"default": "./dist/cjs/index.cjs"
|
|
20
|
+
},
|
|
21
|
+
"browser": "./dist/iife/index.global.js"
|
|
16
22
|
},
|
|
17
23
|
"sideEffects": false,
|
|
18
24
|
"homepage": "https://github.com/sapphiredev/utilities/tree/main/packages/async-queue",
|
|
@@ -20,10 +26,12 @@
|
|
|
20
26
|
"test": "vitest run",
|
|
21
27
|
"lint": "eslint src tests --ext ts --fix -c ../../.eslintrc",
|
|
22
28
|
"docs": "typedoc-json-parser",
|
|
23
|
-
"build": "tsup",
|
|
29
|
+
"build": "yarn gen-index && tsup && yarn build:rename-cjs-index",
|
|
30
|
+
"build:rename-cjs-index": "tsx ../../scripts/rename-cjs-index.cts",
|
|
24
31
|
"prepack": "yarn build",
|
|
25
32
|
"bump": "cliff-jumper",
|
|
26
|
-
"check-update": "cliff-jumper --dry-run"
|
|
33
|
+
"check-update": "cliff-jumper --dry-run",
|
|
34
|
+
"gen-index": "tsx ../../scripts/gen-index.cts async-queue --write"
|
|
27
35
|
},
|
|
28
36
|
"repository": {
|
|
29
37
|
"type": "git",
|
|
@@ -31,9 +39,7 @@
|
|
|
31
39
|
"directory": "packages/async-queue"
|
|
32
40
|
},
|
|
33
41
|
"files": [
|
|
34
|
-
"dist
|
|
35
|
-
"dist/**/*.mjs*",
|
|
36
|
-
"dist/**/*.d*"
|
|
42
|
+
"dist/"
|
|
37
43
|
],
|
|
38
44
|
"engines": {
|
|
39
45
|
"node": ">=v14.0.0",
|
|
@@ -56,12 +62,13 @@
|
|
|
56
62
|
"access": "public"
|
|
57
63
|
},
|
|
58
64
|
"devDependencies": {
|
|
59
|
-
"@favware/cliff-jumper": "^
|
|
60
|
-
"@vitest/coverage-
|
|
61
|
-
"tsup": "^
|
|
62
|
-
"
|
|
63
|
-
"typedoc
|
|
64
|
-
"
|
|
65
|
-
"
|
|
65
|
+
"@favware/cliff-jumper": "^6.0.0",
|
|
66
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
67
|
+
"tsup": "^8.5.0",
|
|
68
|
+
"tsx": "^4.20.6",
|
|
69
|
+
"typedoc": "^0.26.11",
|
|
70
|
+
"typedoc-json-parser": "^10.2.0",
|
|
71
|
+
"typescript": "~5.4.5",
|
|
72
|
+
"vitest": "^3.2.4"
|
|
66
73
|
}
|
|
67
74
|
}
|
package/dist/index.global.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/AsyncQueueEntry.ts","../src/lib/AsyncQueue.ts"],"names":[],"mappings":";;;;;;;;;AAKO,IAAM,kBAAN,MAAsB;AAAA,EAQrB,YAAY,OAAmB;AAPtC,wBAAgB;AAChB,wBAAQ;AACR,wBAAQ;AACR,wBAAiB;AACjB,wBAAQ,UAAqC;AAC7C,wBAAQ,kBAAsC;AAG7C,SAAK,QAAQ;AACb,SAAK,UAAU,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC/C,WAAK,UAAU;AACf,WAAK,SAAS;AAAA,IACf,CAAC;AAAA,EACF;AAAA,EAEO,UAAU,QAAqB;AACrC,QAAI,OAAO;AAAS,aAAO;AAE3B,SAAK,SAAS;AACd,SAAK,iBAAiB,MAAM;AAC3B,YAAM,QAAQ,KAAK,MAAM,UAAU,EAAE,QAAQ,IAAI;AACjD,UAAI,UAAU;AAAI,aAAK,MAAM,UAAU,EAAE,OAAO,OAAO,CAAC;AAExD,WAAK,OAAO,IAAI,MAAM,0BAA0B,CAAC;AAAA,IAClD;AACA,SAAK,OAAO,iBAAiB,SAAS,KAAK,cAAc;AACzD,WAAO;AAAA,EACR;AAAA,EAEO,MAAM;AACZ,SAAK,QAAQ;AACb,SAAK,QAAQ;AACb,WAAO;AAAA,EACR;AAAA,EAEO,QAAQ;AACd,SAAK,QAAQ;AACb,SAAK,OAAO,IAAI,MAAM,0BAA0B,CAAC;AACjD,WAAO;AAAA,EACR;AAAA,EAEQ,UAAU;AACjB,QAAI,KAAK,QAAQ;AAChB,WAAK,OAAO,oBAAoB,SAAS,KAAK,cAAe;AAC7D,WAAK,SAAS;AACd,WAAK,iBAAiB;AAAA,IACvB;AAAA,EACD;AACD;AAjDa;;;ACAN,IAAM,aAAN,MAAiB;AAAA,EAAjB;AAoBN;AAAA;AAAA;AAAA,wBAAQ,YAA8B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAfvC,IAAW,YAAoB;AAC9B,WAAO,KAAK,SAAS;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAW,SAAiB;AAC3B,WAAO,KAAK,cAAc,IAAI,IAAI,KAAK,YAAY;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4BO,KAAK,SAA0D;AACrE,UAAM,QAAQ,IAAI,gBAAgB,IAAI;AAEtC,QAAI,KAAK,SAAS,WAAW,GAAG;AAC/B,WAAK,SAAS,KAAK,KAAK;AACxB,aAAO,QAAQ,QAAQ;AAAA,IACxB;AAEA,SAAK,SAAS,KAAK,KAAK;AACxB,QAAI,SAAS;AAAQ,YAAM,UAAU,QAAQ,MAAM;AACnD,WAAO,MAAM;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,QAAc;AACpB,QAAI,KAAK,SAAS,WAAW;AAAG;AAChC,QAAI,KAAK,SAAS,WAAW,GAAG;AAE/B,WAAK,SAAS,MAAM;AACpB;AAAA,IACD;AAIA,SAAK,SAAS,MAAM;AACpB,SAAK,SAAS,CAAC,EAAE,IAAI;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,WAAiB;AAEvB,QAAI,KAAK,WAAW;AAAG;AAIvB,aAAS,IAAI,GAAG,IAAI,KAAK,SAAS,QAAQ,EAAE,GAAG;AAC9C,WAAK,SAAS,CAAC,EAAE,MAAM;AAAA,IACxB;AAEA,SAAK,SAAS,SAAS;AAAA,EACxB;AACD;AAzFa","sourcesContent":["import type { AsyncQueue } from './AsyncQueue';\n\n/**\n * @internal\n */\nexport class AsyncQueueEntry {\n\tpublic readonly promise: Promise<void>;\n\tprivate resolve!: () => void;\n\tprivate reject!: (error: Error) => void;\n\tprivate readonly queue: AsyncQueue;\n\tprivate signal: PolyFillAbortSignal | null = null;\n\tprivate signalListener: (() => void) | null = null;\n\n\tpublic constructor(queue: AsyncQueue) {\n\t\tthis.queue = queue;\n\t\tthis.promise = new Promise((resolve, reject) => {\n\t\t\tthis.resolve = resolve;\n\t\t\tthis.reject = reject;\n\t\t});\n\t}\n\n\tpublic setSignal(signal: AbortSignal) {\n\t\tif (signal.aborted) return this;\n\n\t\tthis.signal = signal as PolyFillAbortSignal;\n\t\tthis.signalListener = () => {\n\t\t\tconst index = this.queue['promises'].indexOf(this);\n\t\t\tif (index !== -1) this.queue['promises'].splice(index, 1);\n\n\t\t\tthis.reject(new Error('Request aborted manually'));\n\t\t};\n\t\tthis.signal.addEventListener('abort', this.signalListener);\n\t\treturn this;\n\t}\n\n\tpublic use() {\n\t\tthis.dispose();\n\t\tthis.resolve();\n\t\treturn this;\n\t}\n\n\tpublic abort() {\n\t\tthis.dispose();\n\t\tthis.reject(new Error('Request aborted manually'));\n\t\treturn this;\n\t}\n\n\tprivate dispose() {\n\t\tif (this.signal) {\n\t\t\tthis.signal.removeEventListener('abort', this.signalListener!);\n\t\t\tthis.signal = null;\n\t\t\tthis.signalListener = null;\n\t\t}\n\t}\n}\n\ninterface PolyFillAbortSignal {\n\treadonly aborted: boolean;\n\taddEventListener(type: 'abort', listener: () => void): void;\n\tremoveEventListener(type: 'abort', listener: () => void): void;\n}\n","import { AsyncQueueEntry } from './AsyncQueueEntry';\n\n/**\n * The AsyncQueue class used to sequentialize burst requests\n */\nexport class AsyncQueue {\n\t/**\n\t * The amount of entries in the queue, including the head.\n\t * @seealso {@link queued} for the queued count.\n\t */\n\tpublic get remaining(): number {\n\t\treturn this.promises.length;\n\t}\n\n\t/**\n\t * The amount of queued entries.\n\t * @seealso {@link remaining} for the count with the head.\n\t */\n\tpublic get queued(): number {\n\t\treturn this.remaining === 0 ? 0 : this.remaining - 1;\n\t}\n\n\t/**\n\t * The promises array\n\t */\n\tprivate promises: AsyncQueueEntry[] = [];\n\n\t/**\n\t * Waits for last promise and queues a new one\n\t * @example\n\t * ```typescript\n\t * const queue = new AsyncQueue();\n\t * async function request(url, options) {\n\t * await queue.wait({ signal: options.signal });\n\t * try {\n\t * const result = await fetch(url, options);\n\t * // Do some operations with 'result'\n\t * } finally {\n\t * // Remove first entry from the queue and resolve for the next entry\n\t * queue.shift();\n\t * }\n\t * }\n\t *\n\t * request(someUrl1, someOptions1); // Will call fetch() immediately\n\t * request(someUrl2, someOptions2); // Will call fetch() after the first finished\n\t * request(someUrl3, someOptions3); // Will call fetch() after the second finished\n\t * ```\n\t */\n\tpublic wait(options?: Readonly<AsyncQueueWaitOptions>): Promise<void> {\n\t\tconst entry = new AsyncQueueEntry(this);\n\n\t\tif (this.promises.length === 0) {\n\t\t\tthis.promises.push(entry);\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tthis.promises.push(entry);\n\t\tif (options?.signal) entry.setSignal(options.signal);\n\t\treturn entry.promise;\n\t}\n\n\t/**\n\t * Unlocks the head lock and transfers the next lock (if any) to the head.\n\t */\n\tpublic shift(): void {\n\t\tif (this.promises.length === 0) return;\n\t\tif (this.promises.length === 1) {\n\t\t\t// Remove the head entry.\n\t\t\tthis.promises.shift();\n\t\t\treturn;\n\t\t}\n\n\t\t// Remove the head entry, making the 2nd entry the new one.\n\t\t// Then use the head entry, which will unlock the promise.\n\t\tthis.promises.shift();\n\t\tthis.promises[0].use();\n\t}\n\n\t/**\n\t * Aborts all the pending promises.\n\t * @note To avoid race conditions, this does **not** unlock the head lock.\n\t */\n\tpublic abortAll(): void {\n\t\t// If there are no queued entries, skip early.\n\t\tif (this.queued === 0) return;\n\n\t\t// Abort all the entries except the head, that is why the loop starts at\n\t\t// 1 and not at 0.\n\t\tfor (let i = 1; i < this.promises.length; ++i) {\n\t\t\tthis.promises[i].abort();\n\t\t}\n\n\t\tthis.promises.length = 1;\n\t}\n}\n\nexport interface AsyncQueueWaitOptions {\n\tsignal?: AbortSignal | undefined | null;\n}\n"]}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/AsyncQueueEntry.ts","../src/lib/AsyncQueue.ts"],"names":[],"mappings":";;;;;;;;;AAKO,IAAM,kBAAN,MAAsB;AAAA,EAQrB,YAAY,OAAmB;AAPtC,wBAAgB;AAChB,wBAAQ;AACR,wBAAQ;AACR,wBAAiB;AACjB,wBAAQ,UAAqC;AAC7C,wBAAQ,kBAAsC;AAG7C,SAAK,QAAQ;AACb,SAAK,UAAU,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC/C,WAAK,UAAU;AACf,WAAK,SAAS;AAAA,IACf,CAAC;AAAA,EACF;AAAA,EAEO,UAAU,QAAqB;AACrC,QAAI,OAAO;AAAS,aAAO;AAE3B,SAAK,SAAS;AACd,SAAK,iBAAiB,MAAM;AAC3B,YAAM,QAAQ,KAAK,MAAM,UAAU,EAAE,QAAQ,IAAI;AACjD,UAAI,UAAU;AAAI,aAAK,MAAM,UAAU,EAAE,OAAO,OAAO,CAAC;AAExD,WAAK,OAAO,IAAI,MAAM,0BAA0B,CAAC;AAAA,IAClD;AACA,SAAK,OAAO,iBAAiB,SAAS,KAAK,cAAc;AACzD,WAAO;AAAA,EACR;AAAA,EAEO,MAAM;AACZ,SAAK,QAAQ;AACb,SAAK,QAAQ;AACb,WAAO;AAAA,EACR;AAAA,EAEO,QAAQ;AACd,SAAK,QAAQ;AACb,SAAK,OAAO,IAAI,MAAM,0BAA0B,CAAC;AACjD,WAAO;AAAA,EACR;AAAA,EAEQ,UAAU;AACjB,QAAI,KAAK,QAAQ;AAChB,WAAK,OAAO,oBAAoB,SAAS,KAAK,cAAe;AAC7D,WAAK,SAAS;AACd,WAAK,iBAAiB;AAAA,IACvB;AAAA,EACD;AACD;AAjDa;;;ACAN,IAAM,aAAN,MAAiB;AAAA,EAAjB;AAoBN;AAAA;AAAA;AAAA,wBAAQ,YAA8B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAfvC,IAAW,YAAoB;AAC9B,WAAO,KAAK,SAAS;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAW,SAAiB;AAC3B,WAAO,KAAK,cAAc,IAAI,IAAI,KAAK,YAAY;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4BO,KAAK,SAA0D;AACrE,UAAM,QAAQ,IAAI,gBAAgB,IAAI;AAEtC,QAAI,KAAK,SAAS,WAAW,GAAG;AAC/B,WAAK,SAAS,KAAK,KAAK;AACxB,aAAO,QAAQ,QAAQ;AAAA,IACxB;AAEA,SAAK,SAAS,KAAK,KAAK;AACxB,QAAI,SAAS;AAAQ,YAAM,UAAU,QAAQ,MAAM;AACnD,WAAO,MAAM;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,QAAc;AACpB,QAAI,KAAK,SAAS,WAAW;AAAG;AAChC,QAAI,KAAK,SAAS,WAAW,GAAG;AAE/B,WAAK,SAAS,MAAM;AACpB;AAAA,IACD;AAIA,SAAK,SAAS,MAAM;AACpB,SAAK,SAAS,CAAC,EAAE,IAAI;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,WAAiB;AAEvB,QAAI,KAAK,WAAW;AAAG;AAIvB,aAAS,IAAI,GAAG,IAAI,KAAK,SAAS,QAAQ,EAAE,GAAG;AAC9C,WAAK,SAAS,CAAC,EAAE,MAAM;AAAA,IACxB;AAEA,SAAK,SAAS,SAAS;AAAA,EACxB;AACD;AAzFa","sourcesContent":["import type { AsyncQueue } from './AsyncQueue';\n\n/**\n * @internal\n */\nexport class AsyncQueueEntry {\n\tpublic readonly promise: Promise<void>;\n\tprivate resolve!: () => void;\n\tprivate reject!: (error: Error) => void;\n\tprivate readonly queue: AsyncQueue;\n\tprivate signal: PolyFillAbortSignal | null = null;\n\tprivate signalListener: (() => void) | null = null;\n\n\tpublic constructor(queue: AsyncQueue) {\n\t\tthis.queue = queue;\n\t\tthis.promise = new Promise((resolve, reject) => {\n\t\t\tthis.resolve = resolve;\n\t\t\tthis.reject = reject;\n\t\t});\n\t}\n\n\tpublic setSignal(signal: AbortSignal) {\n\t\tif (signal.aborted) return this;\n\n\t\tthis.signal = signal as PolyFillAbortSignal;\n\t\tthis.signalListener = () => {\n\t\t\tconst index = this.queue['promises'].indexOf(this);\n\t\t\tif (index !== -1) this.queue['promises'].splice(index, 1);\n\n\t\t\tthis.reject(new Error('Request aborted manually'));\n\t\t};\n\t\tthis.signal.addEventListener('abort', this.signalListener);\n\t\treturn this;\n\t}\n\n\tpublic use() {\n\t\tthis.dispose();\n\t\tthis.resolve();\n\t\treturn this;\n\t}\n\n\tpublic abort() {\n\t\tthis.dispose();\n\t\tthis.reject(new Error('Request aborted manually'));\n\t\treturn this;\n\t}\n\n\tprivate dispose() {\n\t\tif (this.signal) {\n\t\t\tthis.signal.removeEventListener('abort', this.signalListener!);\n\t\t\tthis.signal = null;\n\t\t\tthis.signalListener = null;\n\t\t}\n\t}\n}\n\ninterface PolyFillAbortSignal {\n\treadonly aborted: boolean;\n\taddEventListener(type: 'abort', listener: () => void): void;\n\tremoveEventListener(type: 'abort', listener: () => void): void;\n}\n","import { AsyncQueueEntry } from './AsyncQueueEntry';\n\n/**\n * The AsyncQueue class used to sequentialize burst requests\n */\nexport class AsyncQueue {\n\t/**\n\t * The amount of entries in the queue, including the head.\n\t * @seealso {@link queued} for the queued count.\n\t */\n\tpublic get remaining(): number {\n\t\treturn this.promises.length;\n\t}\n\n\t/**\n\t * The amount of queued entries.\n\t * @seealso {@link remaining} for the count with the head.\n\t */\n\tpublic get queued(): number {\n\t\treturn this.remaining === 0 ? 0 : this.remaining - 1;\n\t}\n\n\t/**\n\t * The promises array\n\t */\n\tprivate promises: AsyncQueueEntry[] = [];\n\n\t/**\n\t * Waits for last promise and queues a new one\n\t * @example\n\t * ```typescript\n\t * const queue = new AsyncQueue();\n\t * async function request(url, options) {\n\t * await queue.wait({ signal: options.signal });\n\t * try {\n\t * const result = await fetch(url, options);\n\t * // Do some operations with 'result'\n\t * } finally {\n\t * // Remove first entry from the queue and resolve for the next entry\n\t * queue.shift();\n\t * }\n\t * }\n\t *\n\t * request(someUrl1, someOptions1); // Will call fetch() immediately\n\t * request(someUrl2, someOptions2); // Will call fetch() after the first finished\n\t * request(someUrl3, someOptions3); // Will call fetch() after the second finished\n\t * ```\n\t */\n\tpublic wait(options?: Readonly<AsyncQueueWaitOptions>): Promise<void> {\n\t\tconst entry = new AsyncQueueEntry(this);\n\n\t\tif (this.promises.length === 0) {\n\t\t\tthis.promises.push(entry);\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tthis.promises.push(entry);\n\t\tif (options?.signal) entry.setSignal(options.signal);\n\t\treturn entry.promise;\n\t}\n\n\t/**\n\t * Unlocks the head lock and transfers the next lock (if any) to the head.\n\t */\n\tpublic shift(): void {\n\t\tif (this.promises.length === 0) return;\n\t\tif (this.promises.length === 1) {\n\t\t\t// Remove the head entry.\n\t\t\tthis.promises.shift();\n\t\t\treturn;\n\t\t}\n\n\t\t// Remove the head entry, making the 2nd entry the new one.\n\t\t// Then use the head entry, which will unlock the promise.\n\t\tthis.promises.shift();\n\t\tthis.promises[0].use();\n\t}\n\n\t/**\n\t * Aborts all the pending promises.\n\t * @note To avoid race conditions, this does **not** unlock the head lock.\n\t */\n\tpublic abortAll(): void {\n\t\t// If there are no queued entries, skip early.\n\t\tif (this.queued === 0) return;\n\n\t\t// Abort all the entries except the head, that is why the loop starts at\n\t\t// 1 and not at 0.\n\t\tfor (let i = 1; i < this.promises.length; ++i) {\n\t\t\tthis.promises[i].abort();\n\t\t}\n\n\t\tthis.promises.length = 1;\n\t}\n}\n\nexport interface AsyncQueueWaitOptions {\n\tsignal?: AbortSignal | undefined | null;\n}\n"]}
|
package/dist/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/AsyncQueueEntry.ts","../src/lib/AsyncQueue.ts"],"names":[],"mappings":";;;;;;;;;AAKO,IAAM,kBAAN,MAAsB;AAAA,EAQrB,YAAY,OAAmB;AAPtC,wBAAgB;AAChB,wBAAQ;AACR,wBAAQ;AACR,wBAAiB;AACjB,wBAAQ,UAAqC;AAC7C,wBAAQ,kBAAsC;AAG7C,SAAK,QAAQ;AACb,SAAK,UAAU,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC/C,WAAK,UAAU;AACf,WAAK,SAAS;AAAA,IACf,CAAC;AAAA,EACF;AAAA,EAEO,UAAU,QAAqB;AACrC,QAAI,OAAO;AAAS,aAAO;AAE3B,SAAK,SAAS;AACd,SAAK,iBAAiB,MAAM;AAC3B,YAAM,QAAQ,KAAK,MAAM,UAAU,EAAE,QAAQ,IAAI;AACjD,UAAI,UAAU;AAAI,aAAK,MAAM,UAAU,EAAE,OAAO,OAAO,CAAC;AAExD,WAAK,OAAO,IAAI,MAAM,0BAA0B,CAAC;AAAA,IAClD;AACA,SAAK,OAAO,iBAAiB,SAAS,KAAK,cAAc;AACzD,WAAO;AAAA,EACR;AAAA,EAEO,MAAM;AACZ,SAAK,QAAQ;AACb,SAAK,QAAQ;AACb,WAAO;AAAA,EACR;AAAA,EAEO,QAAQ;AACd,SAAK,QAAQ;AACb,SAAK,OAAO,IAAI,MAAM,0BAA0B,CAAC;AACjD,WAAO;AAAA,EACR;AAAA,EAEQ,UAAU;AACjB,QAAI,KAAK,QAAQ;AAChB,WAAK,OAAO,oBAAoB,SAAS,KAAK,cAAe;AAC7D,WAAK,SAAS;AACd,WAAK,iBAAiB;AAAA,IACvB;AAAA,EACD;AACD;AAjDa;;;ACAN,IAAM,aAAN,MAAiB;AAAA,EAAjB;AAoBN;AAAA;AAAA;AAAA,wBAAQ,YAA8B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAfvC,IAAW,YAAoB;AAC9B,WAAO,KAAK,SAAS;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAW,SAAiB;AAC3B,WAAO,KAAK,cAAc,IAAI,IAAI,KAAK,YAAY;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4BO,KAAK,SAA0D;AACrE,UAAM,QAAQ,IAAI,gBAAgB,IAAI;AAEtC,QAAI,KAAK,SAAS,WAAW,GAAG;AAC/B,WAAK,SAAS,KAAK,KAAK;AACxB,aAAO,QAAQ,QAAQ;AAAA,IACxB;AAEA,SAAK,SAAS,KAAK,KAAK;AACxB,QAAI,SAAS;AAAQ,YAAM,UAAU,QAAQ,MAAM;AACnD,WAAO,MAAM;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,QAAc;AACpB,QAAI,KAAK,SAAS,WAAW;AAAG;AAChC,QAAI,KAAK,SAAS,WAAW,GAAG;AAE/B,WAAK,SAAS,MAAM;AACpB;AAAA,IACD;AAIA,SAAK,SAAS,MAAM;AACpB,SAAK,SAAS,CAAC,EAAE,IAAI;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,WAAiB;AAEvB,QAAI,KAAK,WAAW;AAAG;AAIvB,aAAS,IAAI,GAAG,IAAI,KAAK,SAAS,QAAQ,EAAE,GAAG;AAC9C,WAAK,SAAS,CAAC,EAAE,MAAM;AAAA,IACxB;AAEA,SAAK,SAAS,SAAS;AAAA,EACxB;AACD;AAzFa","sourcesContent":["import type { AsyncQueue } from './AsyncQueue';\n\n/**\n * @internal\n */\nexport class AsyncQueueEntry {\n\tpublic readonly promise: Promise<void>;\n\tprivate resolve!: () => void;\n\tprivate reject!: (error: Error) => void;\n\tprivate readonly queue: AsyncQueue;\n\tprivate signal: PolyFillAbortSignal | null = null;\n\tprivate signalListener: (() => void) | null = null;\n\n\tpublic constructor(queue: AsyncQueue) {\n\t\tthis.queue = queue;\n\t\tthis.promise = new Promise((resolve, reject) => {\n\t\t\tthis.resolve = resolve;\n\t\t\tthis.reject = reject;\n\t\t});\n\t}\n\n\tpublic setSignal(signal: AbortSignal) {\n\t\tif (signal.aborted) return this;\n\n\t\tthis.signal = signal as PolyFillAbortSignal;\n\t\tthis.signalListener = () => {\n\t\t\tconst index = this.queue['promises'].indexOf(this);\n\t\t\tif (index !== -1) this.queue['promises'].splice(index, 1);\n\n\t\t\tthis.reject(new Error('Request aborted manually'));\n\t\t};\n\t\tthis.signal.addEventListener('abort', this.signalListener);\n\t\treturn this;\n\t}\n\n\tpublic use() {\n\t\tthis.dispose();\n\t\tthis.resolve();\n\t\treturn this;\n\t}\n\n\tpublic abort() {\n\t\tthis.dispose();\n\t\tthis.reject(new Error('Request aborted manually'));\n\t\treturn this;\n\t}\n\n\tprivate dispose() {\n\t\tif (this.signal) {\n\t\t\tthis.signal.removeEventListener('abort', this.signalListener!);\n\t\t\tthis.signal = null;\n\t\t\tthis.signalListener = null;\n\t\t}\n\t}\n}\n\ninterface PolyFillAbortSignal {\n\treadonly aborted: boolean;\n\taddEventListener(type: 'abort', listener: () => void): void;\n\tremoveEventListener(type: 'abort', listener: () => void): void;\n}\n","import { AsyncQueueEntry } from './AsyncQueueEntry';\n\n/**\n * The AsyncQueue class used to sequentialize burst requests\n */\nexport class AsyncQueue {\n\t/**\n\t * The amount of entries in the queue, including the head.\n\t * @seealso {@link queued} for the queued count.\n\t */\n\tpublic get remaining(): number {\n\t\treturn this.promises.length;\n\t}\n\n\t/**\n\t * The amount of queued entries.\n\t * @seealso {@link remaining} for the count with the head.\n\t */\n\tpublic get queued(): number {\n\t\treturn this.remaining === 0 ? 0 : this.remaining - 1;\n\t}\n\n\t/**\n\t * The promises array\n\t */\n\tprivate promises: AsyncQueueEntry[] = [];\n\n\t/**\n\t * Waits for last promise and queues a new one\n\t * @example\n\t * ```typescript\n\t * const queue = new AsyncQueue();\n\t * async function request(url, options) {\n\t * await queue.wait({ signal: options.signal });\n\t * try {\n\t * const result = await fetch(url, options);\n\t * // Do some operations with 'result'\n\t * } finally {\n\t * // Remove first entry from the queue and resolve for the next entry\n\t * queue.shift();\n\t * }\n\t * }\n\t *\n\t * request(someUrl1, someOptions1); // Will call fetch() immediately\n\t * request(someUrl2, someOptions2); // Will call fetch() after the first finished\n\t * request(someUrl3, someOptions3); // Will call fetch() after the second finished\n\t * ```\n\t */\n\tpublic wait(options?: Readonly<AsyncQueueWaitOptions>): Promise<void> {\n\t\tconst entry = new AsyncQueueEntry(this);\n\n\t\tif (this.promises.length === 0) {\n\t\t\tthis.promises.push(entry);\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tthis.promises.push(entry);\n\t\tif (options?.signal) entry.setSignal(options.signal);\n\t\treturn entry.promise;\n\t}\n\n\t/**\n\t * Unlocks the head lock and transfers the next lock (if any) to the head.\n\t */\n\tpublic shift(): void {\n\t\tif (this.promises.length === 0) return;\n\t\tif (this.promises.length === 1) {\n\t\t\t// Remove the head entry.\n\t\t\tthis.promises.shift();\n\t\t\treturn;\n\t\t}\n\n\t\t// Remove the head entry, making the 2nd entry the new one.\n\t\t// Then use the head entry, which will unlock the promise.\n\t\tthis.promises.shift();\n\t\tthis.promises[0].use();\n\t}\n\n\t/**\n\t * Aborts all the pending promises.\n\t * @note To avoid race conditions, this does **not** unlock the head lock.\n\t */\n\tpublic abortAll(): void {\n\t\t// If there are no queued entries, skip early.\n\t\tif (this.queued === 0) return;\n\n\t\t// Abort all the entries except the head, that is why the loop starts at\n\t\t// 1 and not at 0.\n\t\tfor (let i = 1; i < this.promises.length; ++i) {\n\t\t\tthis.promises[i].abort();\n\t\t}\n\n\t\tthis.promises.length = 1;\n\t}\n}\n\nexport interface AsyncQueueWaitOptions {\n\tsignal?: AbortSignal | undefined | null;\n}\n"]}
|