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



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

以下两个代码段的唯一区别是,在一个代码段中,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((",同步处理程序会以最小的时间差异更快地打印"Time"消息。

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

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

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

所以,当然,有时这种异步技术可能会帮助你(尽管在Javascript中很少处理这种密集型技术,所以通常它根本不会很明显(。

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

不,将async函数用于 DOM 事件处理程序没有任何优势,它所做的只是增加(非常小的一点(开销。

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

最新更新