asfman
android developer
posts - 90,  comments - 213,  trackbacks - 0
 原文地址:http://ejohn.org/blog/how-javascript-timers-work/
 作为基本点去明白js定时器如何工作的是非常重要的。因为js是单线程的所以通常它们表现的和我们直观想像的不太一样。让我们通过查看3个可以构造和操作定时器的函数开始吧。
   1.var id = setTimeout(fn, delay);-初始化一个定时器,在延时后调用指定函数,返回一个以后可以取消定时器的的id.
   2.var id = setInterval(fn, delay);- 类似setTimeout,但会持续的调用指定函数(每次延时后)直到被取消.
   3.clearInterval(id), clearTimeout(id);-接受一个定时器id(可以通过前面任意一个函数返回),终止定时器回调发生。
  为了明白定时器内部是如何工作,有一个重要的概念我们需要仔细查看:定时器的延时是没有保证的。由于所有在游览器执行的js都是单线程异步事件(比如鼠标单击和定时器),执行过程中只有在有空闲的时候才会被执行。通过下图可以很好的说明这一观点:
  
   在上图中有很多信息是需要好好去消化下的,完全理解会让你对js的异步工作有更好的认识。上面图表是一维的:垂直表示时间,按毫秒计算。蓝色的盒子表示正在执行的部分js。如第一个js块执行的时间大约为18ms,鼠标点击块执行的时间大约为11ms,等等。
  因为js只能在某一时刻执行一小段代码(由于它的单线程天性),这些执行代码块中的每个都会"阻塞"其他异步事件的进行。这意味着当一个异步事件发生时(如鼠标单击事件,定时器触发,或者异步请求完成时),它会排队等待执行(至于队列实际上是如何排列的,想必各个游览器表现都会不一样,所以这样考虑是一个简化)。
  一开始在第一个js代码块里,2个定时器被初始化:1个10ms的setTimeout和1个10ms的setInterval。根据定时器何时何地会被初始化,他实际上会在第一个执行块完成之前被触发。注意,不管怎样,它不会被马上执行(由于线程关系,没有能力做到)。相反,延时执行的回调函数会进入队列以便在下一空闲的时刻执行。
   此外,在第一个代码块里,我们看到一个鼠标单击事件发生。一个js回调函数被绑定于这个异步事件(我们不知道用户何时会点击,所以这被认为是异步的),但不会被马上执行,它像开始的那个定时器一样,会进入队列等待执行。
   在第一个js代码块初始化完成后,游览器会立刻询问:谁正在等待执行啊?这种情况下,鼠标单击事件处理函数和定时器回调函数正在等待执行。然后游览器挑选一个(鼠标单击事件处理函数)马上执行,定时器回调函数继续等待下一个可能的时间去执行。
   注意到当鼠标单击回调函数正在执行的时候,第一个interval回调执行,与其他定时器一样,它的回调函数排队等待执行。不管怎样,注意到当interval再次被触发(当最初的那个定时器回调函数执行的时候),这次interval回调函数会被丢弃。当一大块代码正在执行时如果你把所有interval的回调函数都放到队列里的话,代码块执行完成后,结果会有一大堆interval回调函数一个接着一个没有时间间隔地执行,直到全部完成。相反,在把更多的回调函数放入队列之前,游览器更倾向于简单地等待,直到队列里没有这个interval的回调函数。 
   事实上,我们可以看到当interval回调函数正在执行的时候,interval第三次被触发。这给我们一个很重要的信息:interval并不关心当前谁在执行,它的回调函数会不加区分地进入队列,即使存在这个回调函数会被丢弃的可能。
   最后,在第二个interval回调函数执行完成后,我们可以看到没有任何其它东西等待js引擎去执行了,这意味着游览器在等候一个新的异步事件的发生。我们看到50ms处interval再次被触发。这次,没有任何东西阻塞它的执行,所以马上执行。
  我们看一下下面这个例子,能更好的描述setTimeout和setInterval之间的区别。
  setTimeout(function(){
    /* 一些长代码块... */
    setTimeout(arguments.callee, 10);
  }, 10);
 
  setInterval(function(){
    /* 一些长代码块... */
  }, 10);
   第一眼看上去这两段代码也许功能上是一样,但其实并不然。值得注意的是setTimeout代码总是会在10ms以后执行(有可能更长,但不会比10ms少),而setInterval会尝试每隔10ms去执行一次,不管上一个回调函数是否执行完成。

在这里学到了很多东西,我们来概括一下:
  1.js引擎是单线程的,使得异步事件只能进入队列等候执行。
  2.在如何执行异步代码上setTimeout和setInterval有着根本的不同。
  3.如果一个定时器被正在执行的代码阻塞了,它会延迟到下一个可能执行的点再执行(可能会比期望的时间长很多)。
  4.如果interval回调函数执行需要花很长时间的话(比指定的延时长),interval有可能没有延迟背靠背地执行。

上述这一切无疑是很重要的知识,理解js引擎是如果工作的,尤其是大量的典型的异步事件发生时,对于构建一个高效的应用代码片段来说是一个非常有利的基础。
   
posted on 2009-03-24 17:42 汪杰 阅读(740) 评论(1)  编辑 收藏 引用 所属分类: javascript

FeedBack:
# re: how-javascript-timers-work翻译
2013-09-29 13:14 | mroff
翻译的很好!  回复  更多评论
  
只有注册用户登录后才能发表评论。

<2019年10月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

常用链接

留言簿(15)

随笔分类(1)

随笔档案(90)

文章分类(727)

文章档案(712)

相册

收藏夹

http://blog.csdn.net/prodigynonsense

友情链接

最新随笔

搜索

  •  

积分与排名

  • 积分 - 384283
  • 排名 - 6

最新随笔

最新评论

阅读排行榜

评论排行榜