简体   繁体   English

等待异步 function 会暂停执行,即使 function 立即返回

[英]awaiting an async function pauses execution even when the function immediately returns

I've recently ran into a problem that essentially boils down to the following code snippet:我最近遇到了一个问题,基本上可以归结为以下代码片段:

 let a = 0; async function f1(){ // doesn't do anything most of the time } async function f2(){ a++; await f1(); console.log(a); } for (let i=0;i<3;i++){ f2(); }

I have an async function f1 that may do some asynchronous operations, but doesn't do anything most of the time.我有一个异步 function f1可能会执行一些异步操作,但大多数时候不执行任何操作。 It is called and awaited inside another function f2 that may get called rapidly without waiting for the previous call to complete, such as in the for-loop in this example.它在另一个 function f2中被调用并等待,它可能会被快速调用而无需等待前一个调用完成,例如在本例中的 for 循环中。

In this example, I would expect the output to be 1, 2 and 3;在此示例中,我希望 output 为 1、2 和 3; since f1 immediately returns, awaiting it shouldn't pause the execution of f2 , and therefore the code should run synchronously as if there wasn't any async-await involved.由于f1立即返回,等待它不应该暂停f2的执行,因此代码应该同步运行,就好像不涉及任何 async-await 一样。 However, when I test this in chrome or firefox, the output is always 3, 3 and 3, indicating that await f1() paused the execution of f2 and continued with the for-loop instead.但是,当我在 chrome 或 firefox 中对此进行测试时,output 始终为 3、3 和 3,这表明await f1()暂停了f2的执行并继续执行 for 循环。

Similarly, this also causes logic errors in the script I'm trying to write.同样,这也会导致我尝试编写的脚本出现逻辑错误。

What's the reason for this behaviour?这种行为的原因是什么? And is there any way to work around this?有没有办法解决这个问题?

From the mdn web docs on Promise.prototype.then :来自 Promise.prototype.then 上的mdn web 文档:

Once a Promise is fulfilled or rejected, the respective handler function (onFulfilled or onRejected) will be called asynchronously (scheduled in the current thread loop).一旦 Promise 被满足或拒绝,相应的处理程序 function(onFulfilled 或 onRejected)将被异步调用(在当前线程循环中调度)。

Therefore, any code that relies on promises and their then -method will run asynchronously too, even if those promises are already resolved as in the case of your f1 -method.因此,任何依赖于 Promise 及其then方法的代码也将异步运行,即使这些 Promise 已经像您的f1方法那样被解析。

You can work around this to some degree by using custom thenable objects instead:您可以通过使用自定义thenable 对象在某种程度上解决此问题:

 let a = 0; function f1(){ return {then:(onResolve)=>{ onResolve(); // resolves immediately }}; } async function f2(){ a++; f1().then(()=>{ console.log(a); }); } for (let i=0;i<3;i++){ f2(); }

However, returning those from an async function or awaiting them will convert them into normal promises again, causing the code to run asynchronously as before.但是,从异步 function 中返回它们或等待它们将再次将它们转换为正常的 Promise,从而导致代码像以前一样异步运行。

So, if you really want to use async/await, I don't think it's possible to avoid this sort of behaviour;所以,如果你真的想使用 async/await,我认为不可能避免这种行为; a better idea would probably to rewrite your code in such a way that this doesn't cause problems.一个更好的主意可能是以不会引起问题的方式重写您的代码。

You need to await f2();你需要await f2(); in the loop to get the expected output of 1, 2, 3 .在循环中获得预期的 output 的1, 2, 3 Like so:像这样:

(async function() {
    for (let i=0;i<3;i++){
        await f2();
    }
})();

Why?为什么? Because in original code when you don't await f2();因为在原始代码中,当您不await f2(); :

  1. f2() gets called (iteration 1) f2() 被调用(迭代 1)
  2. a gets incremented (iteration 1) a 递增(迭代 1)
  3. the code for f1 is queued (iteration 1) f1 的代码已排队(迭代 1)
  4. f2() gets called (iteration 2) f2() 被调用(迭代 2)
  5. a gets incremented (iteration 2) a 递增(迭代 2)
  6. the code for f1 is queued (iteration 2) f1 的代码已排队(迭代 2)
  7. f2() gets called (iteration 3) f2() 被调用(迭代 3)
  8. a gets incremented (iteration 3) a 递增(迭代 3)
  9. the code for f1 is queued (iteration 3) f1 的代码已排队(迭代 3)
  10. a is now 3 a 现在是 3
  11. Now, queued code is processed if its complete (in any order)现在,排队的代码在其完整时被处理(以任何顺序)
  12. Since, value of a is 3 at this point, any of 3 queued f2 calls that successfully await f1, would print 3 in f2由于此时 a 的值为 3,因此成功等待 f1 的 3 个排队的 f2 调用中的任何一个都将在 f2 中打印 3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM