我遵循本文中的示例https://spin.atomicobject.com/2018/09/10/javascript-concurrency/:
我们这里需要的基本上是一个互斥锁:一种表明读取集合、更新集合和写回集合的临界区不能同时发生的方式。让我们假设我们有这样一个东西[…]:
const collectionMutex = new Mutex(); async function set(collection: string, key: string, value: string): {[key: string]: string} { return await collectionMutex.dispatch(async () => { const data = await fetchCollection(collection); data[key] = val; await sendCollection(collection, data); return data; }); }
实现这个互斥锁需要一点承诺蹦床,但它仍然相对简单:
class Mutex { private mutex = Promise.resolve(); lock(): PromiseLike<() => void> { let begin: (unlock: () => void) => void = unlock => {}; this.mutex = this.mutex.then(() => { return new Promise(begin); }); return new Promise(res => { begin = res; }); } async dispatch(fn: (() => T) | (() => PromiseLike<T>)): Promise<T> { const unlock = await this.lock(); try { return await Promise.resolve(fn()); } finally { unlock(); } } }
在Mutex
类的dispatch
函数中,unlock
设置为await this.lock()
。
我的问题是:当lock()
返回一个不解决任何问题的承诺时,unlock
是如何以及为什么是一个函数;承诺只设置begin = res
。
下面是它的工作原理:
有两个承诺是用new Promise
创建的。其中之一是lock
返回的承诺。我们称这个承诺为P1
。另一个稍后在传递给this.mutex.then
的回调中创建。我们把这个promise命名为P2
。
res
是一个函数,当被调用时,解析P1
。但它不会立即被调用。相反,begin
被用来引用同一个函数(begin = res
),以便我们以后可以访问它。
当给this.mutex.then
的回调被执行时(也就是最近的锁被释放的时候),主要的神奇发生了:
new Promise(begin)
willexecutebegin
。这看起来很奇怪,因为通常情况下,您会提供一个内联回调函数,在其中执行具有一些异步依赖关系的逻辑,然后让它调用resolve
——这个回调函数获得的参数。但是这里begin
是那个回调函数。您可以通过向构造函数提供内联函数包装器,将P2
承诺的创建编写得更详细,如下所示:
new Promise(resolve => begin(resolve));
如前所述,调用begin
将解析P1
。传递给begin
的参数将是承诺构造函数提供给我们的resolve
函数,以便我们可以解析新的P2
承诺。这个(function)参数因此成为P1
的分辨率值,是的,它是一个函数。这就是await
-ed表达式解析的内容。因此,unlock
是resolve
函数,用于解析P2
。