jgb-cli
Version:
```shell npm i -g jgb-cli #全局安装 ```
104 lines (88 loc) • 2.32 kB
text/typescript
export type ICommonFunction<T = any> = (...args: any[]) => T;
export default class PromiseQueue {
process: ICommonFunction<Promise<any>>;
maxConcurrent: number;
retry: boolean;
queue: any[] = [];
processing = new Set();
processed = new Set();
numRunning = 0;
runPromise: Promise<any> = null;
resolve: ICommonFunction = null;
reject: ICommonFunction = null;
constructor(
callback: ICommonFunction<Promise<any>>,
options: {
maxConcurrent?: number;
retry?: boolean;
} = {}
) {
this.process = callback;
this.maxConcurrent = options.maxConcurrent || Infinity;
this.retry = options.retry !== false;
}
add(job: any, ...args: any[]) {
if (this.processing.has(job)) {
return;
}
if (this.runPromise && this.numRunning < this.maxConcurrent) {
this.runJob(job, args);
} else {
this.queue.push([job, args]);
}
this.processing.add(job);
}
run() {
if (this.runPromise) {
return this.runPromise;
}
const runPromise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
this.runPromise = runPromise;
this._next();
return runPromise;
}
private async runJob(job: any, args: any[]) {
try {
this.numRunning++;
await this.process(job, ...args);
this.processing.delete(job);
this.processed.add(job);
this.numRunning--;
this._next();
} catch (err) {
this.numRunning--;
if (this.retry) {
this.queue.push([job, args]);
} else {
this.processing.delete(job);
}
if (this.reject) {
this.reject(err);
}
this._reset();
}
}
_next() {
if (!this.runPromise) {
return;
}
if (this.queue.length > 0) {
while (this.queue.length > 0 && this.numRunning < this.maxConcurrent) {
const [job, args] = this.queue.shift();
this.runJob(job, args);
}
} else if (this.processing.size === 0) {
this.resolve(this.processed);
this._reset();
}
}
_reset() {
this.processed = new Set();
this.runPromise = null;
this.resolve = null;
this.reject = null;
}
}