noname/noname/util/mutex.js

76 lines
1.4 KiB
JavaScript
Raw Normal View History

2024-04-15 19:00:36 +00:00
/**
* 一个非常普通的
*/
export class Mutex {
/**
* 锁目前的状态只有unlockedlocked两种情况
*
* @type {'locked' | 'unlocked'}
*/
#status;
/**
* 上锁后用于等待的锁Promise
*
* @type {null | Promise<void>}
*/
#promise;
/**
* 上锁后用于触发锁Promise的resolve函数
*
* @type {null | function(): void}
*/
#resolve;
constructor() {
this.#status = "unlocked";
this.#promise = null;
this.#resolve = null;
}
/**
* 上锁
*
* 请时刻记住使用`await Mutex#lock()`来使锁正常工作
*/
async lock() {
switch (this.#status) {
case "locked":
await this.#promise;
case "unlocked":
this.#status = "locked";
// @ts-ignore
({ promise: this.#promise, resolve: this.#resolve } = Promise.withResolvers());
break;
}
}
/**
* 解锁
*
* 请不要在未上锁的情况下解锁
*/
unlock() {
if (this.#status === "unlocked") throw new Error("This Mutex is not locked.");
this.#status = "unlocked";
if (this.#resolve) this.#resolve();
}
/**
* 启用锁的try-finally封装用于在函数执行完后自动解放锁的控制权就算发生错误
*
* @param {function(): void | Promise<void>} content
*/
async scoped(content) {
try {
await this.lock();
await content();
} finally {
this.unlock();
}
}
}