当前位置: 首页 > 图文教程 > 网络编程 > Javascript > 解读javascript的计时器(翻译教程)

Javascript
JavaScript DOM学习第八章 表单错误提示
JavaScript DOM 学习第九章 选取范围的介绍
JavaScript CSS修改学习第一章 查找位置
JavaScript CSS修改学习第二章 样式
JavaScript CSS修改学习第三章 修改样式表
JavaScript CSS 修改学习第四章 透明度设置
JavaScript CSS修改学习第五章 给“上传”添加样式
JavaScript CSS修改学习第六章 拖拽
Jquery乱码的一次解决过程 图解教程
javascript 包裹节点 提高效率
javascript inneHTML的地雷
javascript 定义新对象方法
判定对象是否为window的js代码
jquery validator 插件增加日期比较方法
jquery 得到当前页面高度和宽度的两个函数
JavaScript 编写匿名函数的几种方法
jQuery 操作下拉列表框实现代码
jQuery入门问答 整理的几个常见的初学者问题
第一个JavaScript入门基础 document.write输出
javascript入门基础之私有变量

Javascript 中的 解读javascript的计时器(翻译教程)


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-28   浏览: 199 ::
收藏到网摘: n/a

说明:这篇文章节选自John Resig 的《Secrets of the JavaScript Ninja》一书,本人翻译只是供大家学习,翻译不足之处,请斧正。

这篇文章主要从下面几个方面解读计时器:

  1. 计时器概述;
  2. 计时器速度深度探析;
  3. 用计时器处理大量任务;
  4. 利用计时器管理动画;
  5. 较好的计时器测试

计时器是一个我们了解很少且经常被滥用的东西,它是javascript的特色。实际上,在复杂的应用程序开发中,它能为我们提供很多帮助。计时器提供了一个可以将代码片段异步延时执行的能力,javascript生来是单线程的(在一定时间范围内仅一部分js代码能运行),计时器为我们提供了一种避开这种限制的方法,从而开辟了另一条执行代码的蹊径。

有趣的是,与我们普遍接受的观点相反,计时器并不是javascript语言的一部分,而是浏览器引入的方法和对象的一部分。这意味着如果你选择在一个非浏览器的环境运行它,很有可能计时器不存在,你必须使用特定功能推行你自己的版本(如Rhino线程)。

1、计时器是如何工作的

从根本上来说,理解计时器如何工作很重要。通常情况下,计时器的行为并不直观,因为它在一个单独的线程中,让我们从三个函数的测试开始,对于每一个函数我们都有机会构建和控制计时器。

  • 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的差异:

setTimeout(function(){
/* Some long block of code... */
setTimeout(arguments.callee, 10);
}, 10);
setInterval(function(){
/* Some long block of code... */
}, 10);

乍一看,这两段代码似乎功能相同,但并非如此。setTimeout代码在前一个回调函数执行万之后,至少有10ms的延迟(最终可能多些,但至少不会少于此),而setInterval将每隔10ms尝试执行一次回调函数而不管最后一个回调函数何时执行。

这里有很多我们需要了解,让我们回顾一下:

  1. Javascript只有单线程,异步事件被迫排队等候执行;
  2. setTimeout和setInterval在如何执行异步代码方面有根本的区别;
  3. 如果计时器无法立即执行,它将延时到下一个可能的时间执行(这比预想的延迟时间要长一些);
  4. 如果有充分的执行时间,Interval可能会毫无延迟的来回执行。

所有这些无疑是重要的知识,了解Javascript引擎如何工作,特别是有大量异步事件出现时,这使得在构建高级应用代码片段时有一个良好的基础。

2、计时器最小延时时间和可靠性

很明显,你可以延迟几秒钟、几分钟、几小时或任何你你想要的时间间隔,但最不明显的是你能选择的最小延时时间。

在一定程度上,浏览器不能为计时器提供良好的解决方案用以精确的处理它们(因为它们自身受操作系统时间的限制)。但是,纵观所有的浏览器,可以很安全的说,最小延时时间大约是10-15ms。

我们可以对跨平台假定的计时器间歇作简单的分析后得出这一结论。例如,如果我们分析延迟时间为0ms的setInterval,我们会发现在大多数浏览器中的最小延迟时间。

在OS操作系统下的浏览器中:

从左上角开始,依次为:Firefox 2, Safari 3, Firefox 3, Opera 9

在Windows操作系统下得浏览器中:

从左上角开始一次为:Firefox 2, Internet Explorer 6, Firefox 3, Opera 9

上面图表中的线条和数字显示了浏览器同时处理时间间歇的数量,我们可以得出结论:在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有差异,你应该重新思考你应用程序代码的结构)。

未完待续