export default class Queue { private items: Array<() => Promise> = []; private waker: (() => void) | null = null; constructor() { this.processQueue().catch((err) => { throw new Error(`Failed to process a queue: ${err}`); }); } private async processQueue(): Promise { const functionExecutor = this.items.shift(); if (functionExecutor === undefined) { await this.sleep(); } else { await functionExecutor(); } } private async sleep() { await new Promise((resolve) => { this.waker = resolve; }); this.waker = null; } async enqueueAndWait(asyncFunc: () => Promise): Promise { const promise = new Promise((resolve, reject) => { const functionExecutor = async () => { try { resolve(await asyncFunc()); } catch (e) { reject(e); } }; this.items.push(functionExecutor); }); if (this.waker !== null) { this.waker(); } return promise; } }