interface Job { key: string | number; // eslint-disable-next-line func: () => Promise; running: boolean; // eslint-disable-next-line resolve: (result: any) => void; reject: (error: Error) => void; } class Queue { private jobs: Job[]; private concurrent: number; constructor(concurrent = 1) { this.jobs = []; this.concurrent = concurrent; } public execute(func: () => Promise, key: string | number = null): Promise { return new Promise((resolve, reject): void => { this.jobs.push({key, func, running: false, resolve, reject}); this.executeNext(); }); } private async executeNext(): Promise { const job = this.getNext(); if (job) { job.running = true; try { const result = await job.func(); this.jobs.splice(this.jobs.indexOf(job), 1); job.resolve(result); this.executeNext(); } catch (error) { this.jobs.splice(this.jobs.indexOf(job), 1); job.reject(error); this.executeNext(); } } } private getNext(): Job { if (this.jobs.filter((j) => j.running).length > (this.concurrent - 1)) { return null; } for (let i = 0; i < this.jobs.length; i++) { const job = this.jobs[i]; if (!job.running && (!job.key || !this.jobs.find((j) => j.key === job.key && j.running))) { return job; } } return null; } public clear(): void { this.jobs = []; } public count(): number { return this.jobs.length; } } export default Queue;