type Cont = () => void; export class Lock { private readonly queue: Cont[] = []; private acquired = false; public async acquire(): Promise { if (!this.acquired) { this.acquired = true; } else { return new Promise((resolve, _) => { this.queue.push(resolve); }); } } public async release(): Promise { if (this.queue.length === 0 && this.acquired) { this.acquired = false; return; } const continuation = this.queue.shift(); return new Promise((res: Cont) => { continuation!(); res(); }); } public async critical(task: () => Promise) { await this.acquire(); try { return await task(); } finally { await this.release(); } } }