【问题标题】:async vs sync event handlers performance异步与同步事件处理程序的性能
【发布时间】:2019-12-16 06:07:06
【问题描述】:

我创建了一些使用异步和同步事件处理程序的测试。我得出的结论是,使用异步处理程序可以极大地改进我们的代码。

下面两个sn-ps的唯一区别是,在一个sn-ps中,customEventHandlerasync,而在那个处理程序中,它使用await sleep(customEventHandlerSleepTime);而不是sleep(customEventHandlerSleepTime);

  • 异步测试:

<body>
  <div id="event1">
    <div id="event2">
      <div id="event3">
        <div id="event4"></div>
      </div>
    </div>
  </div>
</body>

<script>
  const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
  const customEventHandlerIterationsCount = 1000000;
  const customEventHandlerSleepTime = 500;
  const customEventName = 'customevent';
  const customEvent = new Event('customevent');
  const customEventHandler = async() => {
    for (let i = 0; i < customEventHandlerIterationsCount; ++i) {
      await sleep(customEventHandlerSleepTime);
    }
  };

  document.getElementById('event4').addEventListener(customEventName, customEventHandler);
  document.getElementById('event3').addEventListener(customEventName, customEventHandler);
  document.getElementById('event2').addEventListener(customEventName, customEventHandler);
  document.getElementById('event1').addEventListener(customEventName, customEventHandler);

  (() => {
    const start = new Date().getTime();
    document.getElementById('event4').dispatchEvent(customEvent);
    const end = new Date().getTime();
    console.log('Time: ', (end - start));
  })();
</script>
  • 同步测试:

<body>
  <div id="event1">
    <div id="event2">
      <div id="event3">
        <div id="event4"></div>
      </div>
    </div>
  </div>
</body>

<script>
  const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
  const customEventHandlerIterationsCount = 1000000;
  const customEventHandlerSleepTime = 500;
  const customEventName = 'customevent';
  const customEvent = new Event('customevent');
  const customEventHandler = () => {
    for (let i = 0; i < customEventHandlerIterationsCount; ++i) {
      sleep(customEventHandlerSleepTime).then(() => {});
    }
  };

  document.getElementById('event4').addEventListener(customEventName, customEventHandler);
  document.getElementById('event3').addEventListener(customEventName, customEventHandler);
  document.getElementById('event2').addEventListener(customEventName, customEventHandler);
  document.getElementById('event1').addEventListener(customEventName, customEventHandler);

  (() => {
    const start = new Date().getTime();
    document.getElementById('event4').dispatchEvent(customEvent);
    const end = new Date().getTime();
    console.log('Time: ', (end - start));
  })();
</script>

以上测试的结果是:

  • 异步测试执行时间:~1ms
  • 同步测试执行时间:~1500ms

我做错了什么还是真的?如果我们从 sleep 函数中删除“await”和“.then()”,同步处理程序会以最小的时间差异更快地打印“Time”消息。

基于这个测试,我想知道是否总是(或几乎总是)使用异步处理程序更好,如果我们例如不知道这个处理程序的嵌套函数会发生什么,或者如果我们不直接在处理程序中使用“等待”,最好避免使用异步?也许有更好的方法来测试这个?

【问题讨论】:

    标签: javascript performance async-await event-handling dom-events


    【解决方案1】:

    您在两个 sn-ps 中都进行了繁重的处理。主要区别在于,在第二个(同步)sn-p 中,您一次创建所有 Promise,同步。有大量的承诺,所以创建这么多承诺的开销很大。在第一个(异步)sn-p 中,当事件被调度并且处理程序运行时,您只需同步创建 一个 sleep Promise - 这几乎不需要任何时间,然后是事件完成。然后,作为一个微任务,第二个 Promise 被创建,你等待它解决。然后,作为一个微任务,第三个 Promise 被创建,你等待它解决。等等。

    您在两个 sn-ps 中都进行了繁重的处理,但其中一个是在很长一段时间内交错运行(Promises 串行运行),但另一方面,Promises 全部并行运行,正在初始化立即地。 如果事件是通过 Javascript 触发的(而不是,例如,原生按钮单击),则需要一些时间才能到达 手动触发如果所有繁重的处理都是同步的,则事件。

    所以,当然,有时这种异步技术可能会对您有所帮助(不过,在 Javascript 中处理这种密集型技术非常罕见,因此通常根本不会引起注意)。

    一个更好的选择可能是将繁重的处理转移到网络工作者中 - 这样,处理就在一个完全独立的线程上完成。

    【讨论】:

    • 如果你也可以回答我在 T.J. 的评论。克劳德的回答会很有帮助。感谢您的帮助,谢谢。
    • Nit:在第一个 sn-p 中,第一个 sleep(…) 承诺不是在微任务中创建的,而是作为 customEventHandler() 调用的一部分。
    • @Bergi 是的,这就是 你只能同步创建一个 Promise 部分
    • 啊,我以为是指异步函数调用创建的promise——所以它是同步创建的两个promise,然后等待第一次超时。
    【解决方案2】:

    不,对 DOM 事件处理程序使用 async 函数没有任何好处,它所做的只是增加了 (非常小的一点) 开销。

    您的测试缺少的是函数仍然需要相同的时间来运行,它们只是在您完成测量后稍后执行,所以您看不到它。但是他们仍然需要那个时间,而且它仍然在主 UI 线程上。

    【讨论】:

    • 但是“总是”使用异步有什么缺点吗?我的意思是,如果我们不知道处理程序中调用的函数会发生什么(如果我们用有意义的东西替换睡眠函数),例如任何其他开发人员都可以用他的回调替换 sleep 函数,我们不知道在处理程序实现期间会做什么。
    • @Marcin 同步函数通常比异步函数更容易处理,并且异步函数返回 可能会拒绝的 Promise(但理想情况下,所有 Promise 都应妥善处理 - 和事件如果有一个,处理程序不会处理生成的 Promise,它们只是调用处理程序)。如果您正在做一些可以从await 中受益的事情,当然,请使用async(并使用try/catch 处理可能出现的错误)。否则,async 只是噪音。另见stackoverflow.com/a/51347160
    • 非常感谢您的帮助。祝你有美好的一天。
    猜你喜欢
    • 2011-10-29
    • 1970-01-01
    • 2013-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多