先回顾一下定时器的一些重要知识:
1、Javascript引擎是单线程执行,异步事件必须要排队等待才能执行。
2、如果无法立即执行定时器,该定时器会被推迟到下一个可用的执行时间点上(可能更长,但不会比指定的延迟时间更少)。
3、如果一直被延迟,到最后,Interval间隔定时器可能会无延迟执行,并且同一个interval处理程序的多个实例不能同时进行排队。
4、setTimeout()和setInterval()在触发周期的定义上是完全不同的。
下面是今天的例子。
通常在我们计算大量数据的时候,比如在操纵成千上万个dom元素的时候,可能会出现一种情况---不响应的用户界面,如下面这段代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<table><tbody></tbody></table>
</body>
</html>
<script type="text/javascript">
var tbody = document.getElementsByTagName('tbody')[0];
for(var i = 0; i < 20000; i++) {
var tr = document.createElement("tr");
for(var t = 0; t < 6; t++) {
var td = document.createElement("td");
td.appendChild(document.createTextNode(i + "," + t));
tr.appendChild(td);
}
tbody.appendChild(tr);
}
</script>
在本例中,我们创建了240000个dom节点,并使用大量的单元格来填充一个表格。这是非常昂贵的操作,明显会增加浏览器的执行时间,从而阻止正常的用户交互操作。
在浏览器中执行该代码段,会发现浏览器的刷新按钮有较长一段时间都是正在加载的状态。
接下来我们引入定时器来改善这段代码----即在代码执行的时候定期暂时休息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<table><tbody></tbody></table>
</body>
</html>
<script type="text/javascript">
//建立初始数据
var rowCount = 20000;
var divideInto = 4;
var chunkSize = rowCount/divideInto;
var iteration = 0;
var table = document.getElementsByTagName("tbody")[0];
setTimeout(function generateRows() {
//计算上次中断的地方
var base = (chunkSize) * iteration;
for(var i = 0; i < chunkSize; i++) {
var tr = document.createElement("tr");
for(var t = 0; t < 6; t++) {
var td = document.createElement("td");
td.appendChild(document.createTextNode((i + base) + "," + t + "," + iteration));
tr.appendChild(td);
}
table.appendChild(tr);
}
iteration++;
//调度下一个阶段
if(iteration < divideInto) {
setTimeout(generateRows, 0)
}
}, 0)
</script>
在该修改版本的事例中,我们将冗长的操作拆分成四步小操作,每个操作创建自己的dom节点、这些较小的操作,则不太可能让浏览器挂掉。
注意:我们是如何进行设置的,以便让数据值得控制操作可以根据变量很容易地调整,比方说,我们应该发现,我们需要将操作拆分成10个部分,而不是4个部分。
还有一个与数学有点关系的重要内容需要注意,我们需要跟踪上一次迭代中断的地方,以及如何自动安排下一个迭代,一直到全部结束。
再次在浏览器中运行该段代码,会发现页面几乎在不感知的情况下加载完这么多dom节点了~~~