为了回答您的问题,让我先解释一下您的代码是如何工作的.
了解代码的工作原理
以下步骤解释了代码的执行:
脚本执行开始
调用disallowConcurrency
函数,将initCmp
作为参数传入.cmpConcurrentFunction
被赋予disallowConcurrency
函数的返回值
第一次打cmpConcurrentFunction
,以'I am called 1 second later'
作为参数传递.在调用过程中,inprogressPromise
是Promise.resolve()
返回的已解决promise .等待它会暂停函数的执行.
第二次打cmpConcurrentFunction
,以'I am called 2 seconds later'
作为参数传递.在第二次调用期间,inprogressPromise
仍然是Promise.resolve()
返回的已解决promise .等待它会暂停函数的执行.
脚本的同步执行到此结束.事件循环现在可以开始处理微任务队列
由于第一次调用cmpConcurrentFunction
而暂停的函数被恢复,根据Promise.resolve()
返回的promise 调用then()
方法.inprogressPromise
的值通过向其分配inprogressPromise.then(...)
返回的新promise 来更新
由于第二次调用cmpConcurrentFunction
而暂停的函数被恢复.从第6步,我们知道inprogressPromise
现在是inprogressPromise.then(...)
返回的promise .因此,在上面调用then()
,我们只是创建一个promise 链,在步骤6中创建的promise 链末尾添加一个新的then()
方法调用.
在这一点上,我们有一个链,看起来像这样:
inProgressPromise
.then(() => fn('I am called 1 second later'))
.then(() => fn('I am called 2 seconds later'))
调用前then
个方法的回调函数,然后调用fn
参数,即initCmp
函数.呼叫initCmp
设置一个计时器,该计时器解析promise initCmp
在1秒后返回.当promise 在1秒后得到解决时,控制台上会记录'I am called 1 second later'
.
当解析第一个then
方法的回调函数中第一次调用initComp
函数返回的promise 时,它解析第一个then
方法返回的promise .这导致调用第二个then
方法的回调函数.这将再次调用initComp
函数,然后该函数返回一个新的promise ,并在1秒后解析.
这就解释了为什么2秒后你会看到'I am called 2 seconds later'
个用户登录控制台.
现在回答你的问题:
但我不明白,如果我移除了等待,为什么它还能继续工作
await inprogressPromise
除了暂停对cmpConcurrentFunction
函数的调用之外,在代码中没有其他用途.两个电话都在等待Promise.resolve()
返回的相同promise .
所以等待是没有必要的?为什么?
因为您在控制台上看到的输出不是因为await
,而是因为promise 链(上面的步骤7)是由cmpConcurrentFunction
函数的两次调用构成的.
此外,我还期待这一点能够奏效:
const disallowConcurrency = (fn) => {
let inprogressPromise = Promise.resolve();
return async (...args) => {
await inprogressPromise;
inprogressPromise = fn(...args);
};
};
上面的代码不能像您的原始代码那样工作,因为现在没有构建promise 链,它是原始代码生成的输出的关键.
在disallowConcurrency
的这个实现中,代码的执行如下所述:
调用cmpConcurrentFunction
函数,将'I am called 1 second later'
作为参数传入
等待inprogressPromise
会暂停函数的执行
第二次打cmpConcurrentFunction
,以'I am called 2 seconds later'
作为参数传递
等待inprogressPromise
会暂停函数的执行. At this point, both invocations of cmpConcurrentFunction
are paused and both function invocations are awaiting the same promise that was created as a result of calling Promise.resolve()
.
这是这里的关键点:cmpConcurrentFunction
函数的两个调用都在等待Promise.resolve()
创建的samepromise .为什么两次祈祷都在等待同一个promise ?由于cmpConcurrentFunction
是第二次调用before,因此cmpConcurrentFunction
的第一次调用将恢复并调用initComp
函数
继续第一次调用cmpConcurrentFunction
,调用initComp
函数并将其返回值分配给inprogressPromise
.
调用initComp
函数会设置一个计时器,用于解析promise initComp
函数在1秒后返回的值
继续第二次调用cmpConcurrentFunction
,调用initComp
函数并将其返回值指定给inprogressPromise
,覆盖当前值inprogressPromise
,inprogressPromise
是第一次调用initComp
函数返回的promise .
调用initComp
函数会设置一个计时器,用于解析promise initComp
函数在1秒后返回的值
此时,initComp
函数已被调用两次,设置了两个单独的计时器,每个计时器在1秒后解析各自的promise .
总结disallowConcurrency
函数的原始实现与此实现之间的区别在于,在原始实现中,您有一个promise 链,它会按顺序解析promise ,而在第二个实现中,您有两个separatepromise (彼此不依赖),并且每个promise 都会在1秒后解析.