代码使用方法:
说明:这篇文章节选自John Resig 的《Secrets of the JavaScript Ninja》一书,本人翻译只是供你们学习,翻译不足之处,请斧正。
这篇文章主要从下面几个方面解读计时器:
计时器概述;
计时器速度深度探析;
用计时器处理大量任务;
利用计时器管理动画;
较好的计时器测试
计 时器是一个咱们了解不多且常常被滥用的东西,它是javascript的特点。实际上,在复杂的应用程序开发中,它能为咱们提供不少帮助。计时器提供了一 个能够将代码片断异步延时执行的能力,javascript生来是单线程的(在必定时间范围内仅一部分js代码能运行),计时器为咱们提供了一种避开这种 限制的方法,从而开辟了另外一条执行代码的蹊径。
有趣的是,与咱们广泛接受的观点相反,计时器并非javascript语言的一部分,而是浏览器引入的方法和对象的一部分。这意味着若是你选择在一个非浏览器的环境运行它,颇有可能计时器不存在,你必须使用特定功能推行你本身的版本(如Rhino线程)。
一、计时器是如何工做的
从根本上来讲,理解计时器如何工做很重要。一般状况下,计时器的行为并不直观,由于它在一个单独的线程中,让咱们从三个函数的测试开始,对于每个函数咱们都有机会构建和控制计时器。
var id = setTimeout(fn,delay);启动一个计时器,它将在延迟时间以后调用特定的函数,该函数返回一个惟一的ID,利用这个ID计时器在稍后的时间里被取消;
var id = setInterval(fn,delay);与setTimeout类似,但它不断的调用函数(每隔必定延迟时间)直到它被取消;
clearInterval(id),clearTimeout(id);接受计时器的 ID(由上述任意一个函数返回)并中止调用计时器。
为了理解计时器内部是如何工做的,有一个很重要的概念须要加以探讨:延迟是没法保证的。既然浏览器中全部javascript 是在一个单线程中运行的,那么异步事件(如鼠标点击、计时器)在执行中也只有存在开放状态时才运行,下面这张图很好的说明了这个问题:
这张图有不少信息须要消化,充分理解它将使你对异步js执行有一个更好的认识,图表是一维的,在垂直方向上是时间(挂钟),以毫秒为单位。蓝色盒子表明js执行的比例。例如,第一个javascript块运行时间大约为18秒,鼠标点击大约为11秒等等。
既 然javascript在必定时间内之执行一部分代码(源于单线程的特性),那么这些代码块的每个就被封锁在其它异步事件执行的进程中。这代表当一个异 步事件发生时(如鼠标点击、计时器释放、XMLHttpRequest请求完成),它将排队等候执行(如何排队在不一样浏览器之间是不同的)。
首 先,在第一代码块里,有两个计时器触发:一个是10ms的setTimeout,一个是10ms的setInterval。在第一个代码块真正完成以前, 它实际上已经释放了。可是,注意,它不会当即执行(因为单线程的问题,它无能为力),相反,为了能在下一个可行的时间获得执行,那些延时函数被编入队列。
另外,在第一个代码块内,咱们看到鼠标点击出现。与这个异步事件(咱们永远不知道什么时候执行动做,这样就能够认为它是不一样步的)相关Javascript回调函数跟初始的计时器同样不能当即被执行,它排队等候执行。
在Javascript最初的代码块执行完毕以后,浏览器会发出疑问:正在等候执行的是什么?在这种状况下,鼠标点击处理器和计时器回调函数同时处于等待之中,而后,浏览器将选择一个并当即执行它,计时器函数将等到下一个可能的时间执行。
注 意,当鼠标点击函数处理器执行时,第一个回调函数也在执行,至于计时器,其处理器被编入队列稍后执行。可是,请注意,当Interval再次释放时(在计 时器处理器执行时),计时器执行的时间将减小。若是你在一大块代码执行期间将全部的Interval回调函数编入队列,其结果是一大群Interval回 调函数会毫无延迟的执行,直到所有完成。而浏览器在队列增大以前只是简单的等到没有Interval处理器排队为止(间歇问题)。
事实上,咱们看到这样一个状况:Interval正在执行时,第三个Interval函数将释放。这代表一个重要的事实:Interval对当前正在执行什么不闻不问,它们将不会青红皂白的排队,即便是牺牲回调函数之间的时间也在所不辞。
最后,在第二个Interval函数执行完毕以后,咱们能够看到没有留下任何Javascript引擎执行的东西。也就是说,浏览器在等待一个新的异步事件的出现。Interval再次释放时,咱们在50ms处得到它,但这一次,执行起来没有任何障碍,它当即释放。
咱们来看一个例子,以便更好的说明setTimeout和setInterval的差别:
Select All
setTimeout(function(){ /* Some long block of code... */ setTimeout(arguments.callee, 10); }, 10); setInterval(function(){ /* Some long block of code... */ }, 10);
乍一看,这两段代码彷佛功能相同,但并不是如此。setTimeout代码在前一个回调函数执行万以后,至少有10ms的延迟(最终可能多些,但至少不会少于此),而setInterval将每隔10ms尝试执行一次回调函数而无论最后一个回调函数什么时候执行。
这里有不少咱们须要了解,让咱们回顾一下:
Javascript只有单线程,异步事件被迫排队等候执行;
setTimeout和setInterval在如何执行异步代码方面有根本的区别;
若是计时器没法当即执行,它将延时到下一个可能的时间执行(这比预想的延迟时间要长一些);
若是有充分的执行时间,Interval可能会毫无延迟的来回执行。
全部这些无疑是重要的知识,了解Javascript引擎如何工做,特别是有大量异步事件出现时,这使得在构建高级应用代码片断时有一个良好的基础。
二、计时器最小延时时间和可靠性
很明显,你能够延迟几秒钟、几分钟、几小时或任何你你想要的时间间隔,但最不明显的是你能选择的最小延时时间。
在必定程度上,浏览器不能为计时器提供良好的解决方案用以精确的处理它们(由于它们自身受操做系统时间的限制)。可是,纵观全部的浏览器,能够很安全的说,最小延时时间大约是10-15ms。
咱们能够对跨平台假定的计时器间歇做简单的分析后得出这一结论。例如,若是咱们分析延迟时间为0ms的setInterval,咱们会发如今大多数浏览器中的最小延迟时间。
在OS操做系统下的浏览器中:
从左上角开始,依次为:Firefox 2, Safari 3, Firefox 3, Opera 9
在Windows操做系统下得浏览器中:
从左上角开始依次为:Firefox 2, Internet Explorer 6, Firefox 3, Opera 9
setTimeout(function(){
/* Some long block of code... */
setTimeout(arguments.callee, 10);
}, 10);
setInterval(function(){
/* Some long block of code... */
}, 10);

上面图表中的线条和数字显示了浏览器同时处理时间间歇的数量,咱们能够得出结论:在OS上,浏览器的最小延时时间为10ms,在windows上为15ms。咱们能够经过为计时器提供0(或任何10ms如下的任何数值)做为延时时间获得这个值。 但 有一个例外,IE为setInterval提供德尔延时时间不能为0(即便setTimeou能欣然的接受)。当setInterval的延时时间为0 时,它会转变成setTimeout(仅执行一次回调函数),而咱们能够经过为其提供1ms的延迟来解决这个问题。因为全部浏览器都能自动向上舍入任何低 于最小延时时间的值,因此用1ms与有效的使用0ms同样安全,或更安全(既然IE浏览器如今能工做)。 从这些表中咱们能够获得其它信 息。最重要的是增强了咱们之前所了解到的:浏览器不能保证你所指定的精确的时间间歇。像Firefox 2,Opera 9(OS)在提供可靠的执行率方面有必定的难度。不少与浏览器如何处理Javascript的垃圾回收有关(Firefox 3在Javascript的执行上做了显著的改善,其垃圾回收在这些结果中立竿见影)。 所以,浏览器能够提供很是小的延迟时间,但其精确度得不到保证,那么在使用计时器时,你须要考虑你的应用程序(若是10ms和15ms有差别,你应该从新思考你应用程序代码的结构)。