异步与同步事件处理程序的性能

时间:2019-12-15 11:13:39

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

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

以下两个摘要中的唯一区别是,其中一个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

我做错什么了吗?是真的吗?如果我们从睡眠功能中删除“ await”和“ .then()”,则同步处理程序将以最小的时间差更快地打印“时间”消息。

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

2 个答案:

答案 0 :(得分:2)

不,将async函数用于DOM事件处理程序没有任何好处,它所做的只是增加(很小的一部分)开销。

您缺少的测试是,这些功能仍需要花费相同的时间来运行,它们只是在完成测量后稍后执行,因此您看不到它。但是他们仍然需要花费时间,并且仍然在主UI线程上。

答案 1 :(得分:2)

您在两个代码段中都在进行繁重的处理。主要区别在于,在第二个(同步)代码段中,您要同步一次创建所有Promises。有大量的承诺,因此创建那么多的开销很大。在第一个(异步)代码段中,当调度事件并运行处理程序时,您只能同步创建一个 sleep承诺-几乎不需要时间,然后再进行事件完成。然后,作为一个微任务,创建了第二个Promise,然后等待其解决。然后,作为微任务,创建第三个Promise,然后等待其解决。等等

您在两个片段中都进行了繁重的处理,但是其中一个片段在很长一段时间内错开了(Promises串行运行),而在另一个片段中,Promises全部并行运行,并立即初始化。 如果事件是通过Javascript触发的(而不是例如本机按钮单击),则在手动触发该事件后需要花费一些时间到达行所有繁重的处理都是同步的。

因此,可以肯定的是,有时这种异步技术可能会为您提供帮助(尽管在Javascript中很少处理这种密集型操作,因此通常根本不会引起注意)。

一个更好的选择可能是将繁重的处理移至Web Worker中-这样,处理将在完全独立的线程上完成。