我创建了一个可同步的mixin,它提供了synchronized
函数:
const lock = Symbol('Synchronizable lock');
const queue = Symbol('Synchronizable queue');
export class Synchronizable {
private [lock] = false;
private [queue]: Array<() => void> = [];
public async synchronized<T>(fn: () => Promise<T>): Promise<T> {
while (true) {
if (this[lock]) await new Promise(resolve => this[queue].push(resolve));
else {
this[lock] = true;
try {
return await fn();
} finally {
this[lock] = false;
const tmp = this[queue];
this[queue] = [];
tmp.forEach(e => e());
}
}
}
}
}
但是锁定不是递归的,锁定时锁定对象将导致死锁:
const c = new Synchronizable();
await c.synchronized(() => c.synchronized(async () => void 0));
完整的代码连同测试用例一起上传到github
就像其他任何语言一样,在锁定时保存当前线程ID,然后将保存的线程ID与当前线程ID进行比较,如果匹配继续。
但是javascript不提供线程ID,并且延迟关闭操作不会生成新ID。
跟踪调用堆栈,找到堆栈中的其他任何锁调用,检查是否为相同的锁。
问题在于堆栈跟踪可能不会像setTimeout
那样跟随回调,因此它将无法在回调之前检测到锁定。
答案 0 :(得分:-1)
我发现可以使用第一种方法通过Zone.js实现,其中Zone.js提供了一种定义线程局部变量的方法。