为啥一起运行时 async-await 比 Promise 慢得多

Posted

技术标签:

【中文标题】为啥一起运行时 async-await 比 Promise 慢得多【英文标题】:why is async-await much slower than promises when running them together为什么一起运行时 async-await 比 Promise 慢得多 【发布时间】:2017-11-11 10:47:26 【问题描述】:

我发现在某些情况下运行 async-await 会慢很多。

<html>
  <script>
    function makeAPromise() 
      return Promise.resolve(Math.random());
    

    function usingPromises() 
      const before = window.performance.now();
      return makeAPromise().then((num) => 
        const after = window.performance.now();
        console.log('Total (promises): ', after-before, 'ms');
        return num;
      )
    

    async function usingAwait() 
      const before = window.performance.now();
      const num = await makeAPromise();
      const after = window.performance.now();
      console.log('Total (await): ', after-before, 'ms');
      return num;
    

    function runBoth() 
      usingAwait();
      usingPromises();
    
    
    runBoth();

  </script>

  <button onclick="usingPromises()">usingPromises</button>
  <button onclick="usingAwait()">usingAwait</button>
  <button onclick="runBoth()">both</button>
</html>

IMO,usingPromises 中的 console.log 应打印与usingAwait 中的结果相似的结果。 但实际上,我得到:

总计(承诺):0.25 毫秒

总计(等待):2.065 毫秒

此外,在页面加载后,如果我点击“usingPromises”或“usingAwait”按钮,我会得到每个类似的结果。 (单独跑都快)

总计(承诺):0.060000000026775524 毫秒

总计(等待):0.08999999999650754 毫秒

但如果我点击“both”按钮,“await”版本比 promises 版本慢约 3-4 倍。

我有一个真实的应用程序在初始化时运行了大量的 Promise / async-await 函数,我发现将一些 async-await 函数替换为它们的“相等”的 Promise 版本可以显着缩短加载时间(~200 毫秒)。

有人可以解释这是为什么吗? async-await 不是也使用与承诺(微任务)相同的作业队列吗?对于何时应该使用 Promise 而不是 async-await 是否有最佳实践?

在 mac 上运行 chrome 62

谢谢

【问题讨论】:

实际上,在 Mac 上运行 Chrome 也一样,async-await 在这里要快得多:Total (await): 0.07500000000004547 msTotal (promises): 0.75 ms。可能是硬件相关的事情。 Async-Await 在内部使用 Promises。 注意:调用 runBoth 会产生扭曲的结果,因为承诺的解决方案在事件队列中是按顺序排列的:所以一个在另一个之前使用 console.log 打印,而 console.log 是给第二个带来额外的延迟。如果您将runBoth 定义为Promise.resolve().then(usingAwait).then(usingPromises),这已经是一种改进。 【参考方案1】:

当您使用按钮 Both 运行时,您的第一个结果具有误导性。承诺解决方案在微任务事件队列中按顺序排列:因此一个可以在另一个之前使用console.log 打印,但正是console.log 给第二个带来了额外的延迟,因为它发生在第二个承诺的创建和对其分辨率的处理。

如果您将runBoth 定义为:

Promise.resolve().then(usingAwait).then(usingPromises)

现在两个 Promise 都将在微任务中创建,第一个 Promise 将在创建第二个 Promise 之前解决和处理。这将导致更公平的比较,其中console.log 没有在任何时间测量。

【讨论】:

以上是关于为啥一起运行时 async-await 比 Promise 慢得多的主要内容,如果未能解决你的问题,请参考以下文章

在 .net 4 上使用 async-await

为啥默认情况下所有函数都不应该是异步的?

为啥这个回调会产生无限循环

为啥我的测试一起运行时通过,但单独失败?

当我对一个程序进行采样并且它实际上比不进行分析时运行得更快时,为啥会这样?

为啥水豚功能规格一起运行时会失败,仅对我而言。但分开时通过?