使用|使用 setTimeout 拆解一些 CPU 密集型的执行任务
未优化之前的版本:
let i = 0;
let start = Date.now();
function count() {// do a heavy job
for (let j = 0;
j < 1e9;
j++) {
i++;
}alert("Done in " + (Date.now() - start) + 'ms');
}count();
上述 count 函数里的 for 循环的 i 累加,是一个 CPU 密集型任务,在执行完毕之前,JavaScript 引擎任务队列里的其他任务,没有机会得到执行。
优化版本 将 i 从 1 累加到 1e9 的任务,拆解成 1000 个小的子任务。每个子任务执行完毕之后,调用
setTimeout
调度自身,这样任务队列里其他任务有机会得到执行。let i = 0;
let start = Date.now();
function count() {// do a piece of the heavy job (*)
do {
i++;
} while (i % 1e6 != 0);
if (i == 1e9) {
alert("Done in " + (Date.now() - start) + 'ms');
} else {
setTimeout(count);
// schedule the new call (**)
}}count();
- 第一轮任务执行:i=1...1000000
- 第二轮任务执行:i=1000001..2000000
现在,如果在引擎忙于执行第 1 部分时出现新的辅助任务(例如 onclick 事件),它会排队,然后在第 1 部分完成时执行,然后再执行下一部分。 在 count 执行之间,使用
setTimeout
定期返回事件循环,为 JavaScript 引擎提供了调度执行其他任务的机会,以对其他用户操作做出反应。let i = 0;
let start = Date.now();
function count() {// move the scheduling to the beginning
if (i < 1e9 - 1e6) {
setTimeout(count);
// schedule the new call
}do {
i++;
} while (i % 1e6 != 0);
if (i == 1e9) {
alert("Done in " + (Date.now() - start) + 'ms');
}}count();
为浏览器脚本拆分 CPU 密集型任务的另一个好处是我们可以显示进度指示。
如前所述,只有在当前运行的任务完成后才会绘制对 DOM 的更改,无论当前运行的任务需要多长时间才能执行完毕。
下面是一个例子:
对 i 的更改要等到函数执行完成后才会显示,所以我们只会看到最后一个值。
但我们也可能想在任务期间展示一些东西,例如一个进度条。
【使用|使用 setTimeout 拆解一些 CPU 密集型的执行任务】如果我们使用 setTimeout 将繁重的任务拆分为多个部分,那么 i 会在多个部分执行之间绘制出来。
推荐阅读
- Delphi使用iTools安卓模拟器
- 使用TensorFlow 2.0创作音乐
- 使用NLTK的初学者文本分析
- canvas 2 image的使用小心得
- android studio 环境配置及使用时遇到的问题
- Python Print()函数
- Python Range()函数
- 使用maven的mybatis-generator代码生成器插件生成实体类mapper配置文件和mapper接口(使用idea)
- Android广播的使用(自定义广播和本地广播)
- Android广播的使用(动态注册和静态注册)