JS计数器函数执行过程解读
1、昂贵计算的处理
在复杂Javascript应用程序开发中,最复杂的可能是用户界面的单线程特性。而Javascript在处理用户交互时最好的状况是反应迟钝,最糟糕的情况是无响应而导致浏览器挂起(在Javascript执行时,页面中所有的更新操作暂停)。源于这一事实,将所有复杂操作(任何多于100ms的计算)减小到可管理的程度就势在必行。另外,如果运行了至少5秒钟还没有停止,一些浏览器(如Firefox 、Opera)将产生一个提示框警告用户脚本无相应。
这显然是不可取的,产生一个无响应的界面并不好。但是,几乎可以肯定的是,当你需要处理大量数据时就会出现这种情况(如处理数以千计的DOM元素会导致这种情况出现)。
此时,计时器就显得尤为有用。由于计时器能有效的暂停Javascript代码的执行,它也能阻止浏览器将执行的代码挂起(只要个别代码还不足以使浏览器挂起)。想到这一点,我们可以将正常的、密集的、循环计算纳入到非阻塞的计算之中,让我们看看下面这个例子,这种类型的计算是必需的。
一个长时运行的任务:
<table><tbody></tbody></table>
// Normal, intensive, operation
var table = document.getElementsByTagName("tbody");
for ( var i = 0; i < 2000; i++ ) {
var tr = document.createElement("tr");
for ( var t = 0; t < 6; t++ ){
var td = document.createElement("td");
td.appendChild( document.createTextNode("" + t));
tr.appendChild( td );
}
table.appendChild( tr );
}
}
在这个例子中,我们创建了总数为26000个DOM节点,并将数字填入表中,这太昂贵了,很有可能将浏览器挂起以阻止用户正常的交互。我们可以将计时器引入其中,从而得到与众不同,也许更好的结果。
用计时器将耗时较长的任务拆分开来:
<table><tbody></tbody></table>
var table = document.getElementsByTagName("tbody");
var i = 0, max = 1999;
setTimeout(function(){
for ( var step = i + 500; i < step; i++ ) {
var tr = document.createElement("tr");
for ( var t = 0; t < 6; t++ ){
var td = document.createElement("td");
td.appendChild( document.createTextNode("" + t));
tr.appendChild( td );
}
}
table.appendChild( tr );
}
if ( i < max )
setTimeout( arguments.callee, 0 );
}, 0);
在我们修改的例子中,我们将密集的计算分成四部分,每个创建6500个节点。这些计算不太可能中断浏览器正常的流。最糟糕的情况也只是这些数字可能随时调整(例如,使其在250-500之间变化,这样我们的每一个单元将产生3500DOM个节点)。但是,给人印象最深的是我们如何改变我们的代码以适应新的异步系统。我们需要做更多的工作以确保元素的数字正确生成(该循环不会永无休止)。这些代码与我们初始的很相似。注意,我们使用闭包维持代码片段间的迭代状态,毫无疑问,不使用闭包,此代码将更为复杂。
与原来的技术相比,使用该技术有一个明显的变化。浏览器的长时挂起被4个视觉化的页面更新替代。虽然浏览器尝试着尽可能快得去执行这些代码片段,它也在计时器的每一步操作之后渲染DOM变化(就好像大量的更新)。大多数情况下,用户觉察不到此种类型的更新,但记住它们曾经发生过很重要。
有一种情况会使该技术能专门为我服务--我构建的计算大学生日程排列的应用程序。起初,该应用程序是典型的CGI(客户与服务器交流,服务器计算出日程表之后将其返回)。但我对它作了改变,讲所有的日程计算放到客户端,这是日程计算的视图:
这些计算的代价相当昂贵(需要遍历数以千计的排列以找到正确的答案)。将日程计算分割成实实在在的单元使这一问题得到了解决(用已经完成的那部分更新用户界面)。最后,用户提交的是快速、反应灵敏、可用性较高的用户界面。
如此有用的技术常常令人惊奇。你会发现它经常被用于长时运行的程序之中,就像测试箱(我们在这章末尾讨论它)。更为重要的是,这种技术向我们显示了解决浏览器环境的限制是多么的轻而易举,同时也为用户提供了丰富的经验。