在JavaScript中,有很多方法可以将长任务拆分。
It's not hard to bork your site's user experience by letting a long, expensive task hog the main thread. No matter how complex an application becomes, the event loop can still do only one thing at a time. If any of your code is squatting on it, everything else is on standby, and it usually doesn't take long for your users to notice.
让一个长时间、耗费资源的任务占用主线程会让你的网站用户体验变得糟糕。这无论应用程序变得多复杂,事件循环仍然只能同时做 一件事。如果你的任何代码在占用它,其他所有代码都处于待机状态,用户通常很快就会注意到这一点。
Here's a contrived example: we have a button for incrementing a count on the screen, alongside a big ol' loop doing some hard work. It's just running a synchronous pause, but pretend this is something meaningful that you, for whatever reason, need to perform on the main thread – and in order.
这是一个牵强的例子:我们有一个按钮用于在屏幕上增加计数,同时还有一个大循环在进行一些繁重的工作。它只是运行一个同步暂停,但假装这是一件有意义的事情,你出于某种原因需要在主线程上执行 - 并且是按顺序的。
<button id="button">count</button>
<div>Click count: <span id="clickCount">0</span></div>
<div>Loop count: <span id="loopCount">0</span></div> <script> function waitSync(milliseconds) { const start = Date.now(); while (Date.now() - start < milliseconds) {} } button.addEventListener("click", () => { clickCount.innerText = Number(clickCount.innerText) + 1; }); const items = new Array(100).fill(null); for (const i of items) { loopCount.innerText = Number(loopCount.innerText) + 1; waitSync(50); }
</script>
When you run this, nothing visually updates – not even the loop count. That's because the browser never gets a chance to paint to the screen. This is all you get, no matter how furiously you click. Only when the looping is completely finished do you get any feedback.
当你运行这个时,视觉上没有任何更新——甚至循环计数也没有。这是因为浏览器根本没有机会绘制到屏幕上。无论你点击得多么猛烈,你得到的就是这些。只有当循环完全结束时,你才会得到任何反馈。
The dev tools flame chart corroborates this. That single task in the event loop takes five seconds to complete. Horrrrrible.
开发者工具的火焰图证实了这一点。事件循环中的那个单一任务需要五秒才能完成。太可怕了。
If you've been in a similar situation before, you know that the solution is periodically break that big task up across multiple ticks of the event loop. This gives other part...