异步与同步事件处理程序性能
async vs sync event handlers performance
我创建了一些使用异步和同步事件处理程序的测试。我得出的结论是,使用异步处理程序可以极大地改进我们的代码。
下面两个片段的唯一区别是,在一个片段中,customEventHandler
是 async
,而在该处理程序中,它使用 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" 最好避免使用异步?也许有更好的方法来测试这个?
不,对 DOM 事件处理程序使用 async
函数没有任何优势,它所做的只是添加 (非常小的一点) 开销.
您的测试缺少的是,这些函数仍然需要相同的时间 运行,它们只是在您完成测量后 稍后 执行,所以你看不到它。但他们仍然需要时间,而且它仍在主线程 UI 上。
您在两个片段中都进行了大量处理。主要区别在于,在第二个(同步)片段中,您一次性创建所有 Promise,同步。有大量的承诺,因此创建如此多的承诺的开销很大。在第一个(异步)片段中,当事件被调度并且处理程序 运行s 时,您只同步创建 one sleep
Promise - 这几乎不需要时间,然后事件结束。然后,作为一个微任务,第二个 Promise 被创建,你等待它 resolve。然后,作为一个微任务,第三个 Promise 被创建,你等待它 resolve。等等
您在两个片段中都进行了繁重的处理,但在一个片段中,它在很长一段时间内错开(Promises 运行 连续),但在另一个片段中,Promises all 运行 并行,立即初始化。 如果事件是通过Javascript触发的(而不是,例如,本地按钮点击),需要一些时间才能到达之后的行 如果所有繁重的处理都是同步的,则手动触发事件。
所以,当然,有时这种异步技术可能会对您有所帮助(尽管如此密集的处理在 Javascript 中非常罕见,因此通常根本不会引起注意)。
更好的选择可能是将繁重的处理转移到网络工作者中 - 这样,处理就在 完全独立的 线程上完成。
我创建了一些使用异步和同步事件处理程序的测试。我得出的结论是,使用异步处理程序可以极大地改进我们的代码。
下面两个片段的唯一区别是,在一个片段中,customEventHandler
是 async
,而在该处理程序中,它使用 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" 最好避免使用异步?也许有更好的方法来测试这个?
不,对 DOM 事件处理程序使用 async
函数没有任何优势,它所做的只是添加 (非常小的一点) 开销.
您的测试缺少的是,这些函数仍然需要相同的时间 运行,它们只是在您完成测量后 稍后 执行,所以你看不到它。但他们仍然需要时间,而且它仍在主线程 UI 上。
您在两个片段中都进行了大量处理。主要区别在于,在第二个(同步)片段中,您一次性创建所有 Promise,同步。有大量的承诺,因此创建如此多的承诺的开销很大。在第一个(异步)片段中,当事件被调度并且处理程序 运行s 时,您只同步创建 one sleep
Promise - 这几乎不需要时间,然后事件结束。然后,作为一个微任务,第二个 Promise 被创建,你等待它 resolve。然后,作为一个微任务,第三个 Promise 被创建,你等待它 resolve。等等
您在两个片段中都进行了繁重的处理,但在一个片段中,它在很长一段时间内错开(Promises 运行 连续),但在另一个片段中,Promises all 运行 并行,立即初始化。 如果事件是通过Javascript触发的(而不是,例如,本地按钮点击),需要一些时间才能到达之后的行 如果所有繁重的处理都是同步的,则手动触发事件。
所以,当然,有时这种异步技术可能会对您有所帮助(尽管如此密集的处理在 Javascript 中非常罕见,因此通常根本不会引起注意)。
更好的选择可能是将繁重的处理转移到网络工作者中 - 这样,处理就在 完全独立的 线程上完成。