import { v4 as uuid } from 'uuid'; type Job<ResultType> = (() => PromiseLike<ResultType>) | (() => ResultType); // TODO: This needs to replace js/modules/job_queue.js export class JobQueue { private pending: Promise<any> = Promise.resolve(); private readonly jobs: Map<string, Promise<unknown>> = new Map(); public has(id: string): boolean { return this.jobs.has(id); } public async add<Result>(job: Job<Result>): Promise<Result> { const id = uuid(); return this.addWithId(id, job); } public async addWithId<Result>( id: string, job: Job<Result> ): Promise<Result> { if (this.jobs.has(id)) { return this.jobs.get(id) as Promise<Result>; } // tslint:disable-next-line: no-promise-as-boolean const previous = this.pending || Promise.resolve(); this.pending = previous.then(job, job); const current = this.pending; void current .catch(() => { // This is done to avoid UnhandledPromiseError }) .finally(() => { if (this.pending === current) { delete this.pending; } this.jobs.delete(id); }); this.jobs.set(id, current); return current; } }