Skip to content

Commit 87bca5d

Browse files
committed
增强 AsyncQueue 类的文档注释,改进代码可读性
1 parent 69ff898 commit 87bca5d

File tree

2 files changed

+192
-186
lines changed

2 files changed

+192
-186
lines changed

src/index.ts

Lines changed: 70 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,49 @@ export interface AsyncQueueOptions {
1616
}
1717

1818
export class AsyncQueue implements Disposable {
19-
/** @internal */
19+
/**
20+
* Maximum number of concurrent tasks
21+
* @internal
22+
*/
2023
private _concurrency: number;
21-
/** @internal */
24+
/**
25+
* Currently running tasks count
26+
* @internal
27+
*/
2228
private _running = 0;
23-
/** @internal */
29+
/**
30+
* Pending task queue
31+
* @internal
32+
*/
2433
private _queue: Task[] = [];
25-
/** @internal */
26-
private __paused = false;
27-
/** @internal */
34+
/**
35+
* Whether the queue is paused
36+
* @internal
37+
*/
38+
private _paused = false;
39+
/**
40+
* Completed task count
41+
* @internal
42+
*/
2843
private _completed = 0;
29-
/** @internal */
30-
private _pendingResolves: Function[] = [];
44+
/**
45+
* Resolvers waiting for all tasks to complete
46+
* @internal
47+
*/
48+
private _pendingResolves: (() => void)[] = [];
3149

3250
/**
3351
* Creates an AsyncQueue instance.
34-
* @param options - The options to create the queue with.
52+
* @param options - Configuration options for the queue.
3553
*/
3654
constructor(options: AsyncQueueOptions = {}) {
37-
const { concurrency = 1 } = options;
38-
this._concurrency = concurrency;
55+
this.setConcurrency(options.concurrency ?? 1);
3956
}
4057

4158
/**
4259
* Adds a task to the queue.
43-
* @param task - The task to add. Should return a Promise.
44-
* @param args - The arguments to call the task with.
60+
* @param task - The task function (must return a Promise).
61+
* @param args - Arguments for the task function.
4562
*/
4663
enqueue<T extends (...args: any[]) => any>(task: T, ...args: Parameters<T>): Promisify<ReturnType<T>> {
4764
return new Promise((resolve, reject) => {
@@ -51,38 +68,26 @@ export class AsyncQueue implements Disposable {
5168
}
5269

5370
/**
54-
* Runs the next task in the queue (if concurrency limit allows).
71+
* Runs the next task in the queue, respecting concurrency limits.
5572
* @internal
5673
*/
5774
private _runNext() {
58-
// If the queue is paused, do not run any tasks
59-
if (this.__paused) {
60-
return;
61-
}
62-
63-
// If the maximum concurrency is reached, do not run any tasks
64-
if (this._running >= this._concurrency) {
65-
return;
66-
}
67-
68-
// If the queue is empty and no tasks are running, resolve all pending promises
69-
if (this._running === 0 && this._queue.length === 0) {
70-
while (this._pendingResolves.length > 0) {
71-
const resolve = this._pendingResolves.shift();
72-
resolve?.();
73-
}
74-
return;
75-
}
75+
if (this._paused || this._running >= this._concurrency) return;
7676

77-
// If the queue is empty, return
7877
if (this._queue.length === 0) {
78+
// Queue is empty, resolve pending promises
79+
if (this._running === 0) {
80+
const pending = this._pendingResolves.splice(0);
81+
pending.forEach((resolve) => resolve());
82+
}
7983
return;
8084
}
8185

8286
const { task, args, resolve, reject } = this._queue.shift() as Task;
8387
this._running++;
8488

85-
task(...args)
89+
Promise.resolve()
90+
.then(() => task(...args))
8691
.then(resolve)
8792
.catch(reject)
8893
.finally(() => {
@@ -92,99 +97,79 @@ export class AsyncQueue implements Disposable {
9297
});
9398
}
9499

95-
/**
96-
* Gets the current number of running tasks in the queue.
97-
*/
98-
get running() {
100+
/** Gets the current number of running tasks. */
101+
get running(): number {
99102
return this._running;
100103
}
101104

102-
/**
103-
* Gets the number of completed tasks in the queue.
104-
*/
105-
get completed() {
105+
/** Gets the number of completed tasks. */
106+
get completed(): number {
106107
return this._completed;
107108
}
108109

109-
/**
110-
* Gets the number of pending tasks in the queue.
111-
*/
112-
get pending() {
110+
/** Gets the number of pending tasks in the queue. */
111+
get pending(): number {
113112
return this._queue.length;
114113
}
115114

116-
/**
117-
* Gets the current number of concurrent tasks.
118-
*/
115+
/** Gets the current concurrency limit. */
119116
get concurrency(): number {
120117
return this._concurrency;
121118
}
122119

123120
/**
124-
* Dynamically updates the number of concurrent tasks.
125-
* @param concurrency - The new number of concurrent tasks.
121+
* Updates the concurrency limit and attempts to run more tasks.
122+
* @param concurrency - New concurrency level.
126123
*/
127-
setConcurrency(concurrency: number) {
128-
this._concurrency = concurrency;
124+
setConcurrency(concurrency: number): void {
125+
if (concurrency < 1 || Number.isNaN(concurrency) || !Number.isFinite(concurrency) || !Number.isInteger(concurrency)) {
126+
throw new RangeError("Concurrency must be a positive integer.");
127+
}
128+
this._concurrency = Math.max(1, concurrency);
129129
this._runNext();
130130
}
131131

132-
/**
133-
* Clears the remaining queue without rejecting tasks.
134-
*/
132+
/** Clears the remaining tasks in the queue. */
135133
clear(): void {
136-
this._queue = [];
134+
this._queue.length = 0;
135+
this._runNext();
137136
}
138137

139-
/**
140-
* Pauses the queue processing.
141-
*/
138+
/** Pauses the execution of queued tasks. */
142139
pause(): void {
143-
this.__paused = true;
140+
this._paused = true;
144141
}
145142

146-
/**
147-
* Resumes the queue processing.
148-
*/
143+
/** Resumes execution of tasks in the queue. */
149144
resume(): void {
150-
if (this.__paused) {
151-
this.__paused = false;
145+
if (this._paused) {
146+
this._paused = false;
152147
this._runNext();
153148
}
154149
}
155150

156-
/**
157-
* Waits for all tasks to complete.
158-
*/
151+
/** Waits for all queued and running tasks to complete. */
159152
waitForAll(): Promise<void> {
160-
if (this._running === 0 && this._queue.length === 0) {
161-
return Promise.resolve(); // Queue is empty, return immediately
162-
}
163-
return new Promise((resolve) => {
164-
this._pendingResolves.push(resolve);
165-
});
153+
return this._running === 0 && this._queue.length === 0
154+
? Promise.resolve()
155+
: new Promise((resolve) => this._pendingResolves.push(resolve));
166156
}
167157

168-
/**
169-
* Releases resources, clears the queue, and ensures unexecuted tasks are rejected.
170-
*/
158+
/** Disposes of the queue, rejecting any pending tasks. */
171159
dispose(): void {
172-
while (this._queue.length > 0) {
160+
while (this._queue.length) {
173161
const { reject } = this._queue.shift() as Task;
174162
reject(new Error("Queue disposed before execution."));
175163
}
164+
this._pendingResolves.length = 0;
176165
}
177166

178-
/**
179-
* Releases resources, clears the queue, and ensures unexecuted tasks are rejected.
180-
*/
167+
/** Implements Disposable interface cleanup. */
181168
[Symbol.dispose]() {
182169
this.dispose();
183170
}
184171

185-
/**
186-
* Returns the string representation of the object.
187-
*/
172+
/** Returns a string tag for debugging. */
188173
get [Symbol.toStringTag]() {
189174
return "AsyncQueue";
190175
}

0 commit comments

Comments
 (0)