首页 > 其他 > 详细

setTimeout setInterval 学习笔记

时间:2014-02-23 00:34:29      阅读:286      评论:0      收藏:0      [点我收藏+]

  两个都是定时函数,setTimeout()只执行一次,setInterval()按时间段循环执行。

  现在有这样一个问题,在函数中递归调用setTimeout()可以达到和setInterval()一样的效果,如下:

bubuko.com,布布扣
1.
function test() {
    setTimeout(test, 10);
    //do something
}

2.  
function test(){...}
setInterval(test, 10);
bubuko.com,布布扣

 

 看起来效果一样,但是John Resig告诉我们由于setInterval()的实现机制,导致上面两种方法大有区别:

原文  http://ejohn.org/blog/how-javascript-timers-work/

文章大意是,对函数func(),时间长度t::

  1.  javascript为单线程执行,因此同一时刻只能有一个函数执行。浏览器会从待执行队列q 中以一定优先级选择函数执行。
  2.  setTimeout: 从当前时刻开始计算,在t 时间后将func()加入待执行函数队列q。
  3.  setInterval: 从当前时刻开始计算,每隔t 时间会将func()加入q中一次。直到执行clearInterval()为止。

  setInterval()这样处理可能产生一个问题,当func()因为某些原因而延迟执行时,可能导致多个func()在短时间内执行多次。这可能由于func()自身执行时间过长,或者是q中其它函数竞争导致func()一直无法执行。这显然属于逻辑出了问题。

  实验:

bubuko.com,布布扣
 1 function test() {
 2     var t = new Date();
 3     console.log("start: "+ t.getSeconds() + "." + t.getMilliseconds());
 4 
 5     var times = 0;
 6     while((new Date() - t)<3000) {
 7         times++;
 8     }
 9 
10     t = new Date();
11     console.log("end: "+ t.getSeconds() + "." + t.getMilliseconds());
12 }
13 
14 var id = setInterval(test,2000);
bubuko.com,布布扣

  每个test()执行时间为3s,每隔2s执行一次test()。那么1个test()还没有执行完第2个test()就已经加入到q中了。实验结果如下:

bubuko.com,布布扣

  可以看到test()函数连续执行,没有像预期一样每隔2s执行一次。

  而 setTimeout() 的处理方式就不会产生这种问题,由于setTimeout()每次都是基于当前时间,而且必须是在func()得到执行时才会产生下一次执行机会。则当CPU繁忙时其执行次数大大小于setInterval()方式。因此setTimeout()方式有在有助于缓解CPU与内存的压力,但是如果我们对func()的执行次数有要求还是需要使用setInterval(),因为该方法不会因为函数延迟执行导致执行次数减少。

 

clearTimeout 与 clearInterval

  两者根据func()的注册id来取消尚未执行的函数,动作是将其从q中移除。但是两者都无法阻止正在执行的func(),此时func()会正常执行到结束。对于setInterval()这种情况很好处理,但是对于setTimeout()可能导致其clear不成功。

  由于setTimeout()每次都会产生一个新的id,又由于单线程的并发性,因此导致了清理的不确定性。如下:

 

1 var test = function() {
2     //do something   
3     id = setTimeout(test, 1000); //put at top to clear the next func
4     //do something
5 }

   id保存最新的待清理函数标识,假设此时id为20。当编号为20的test()执行到第2行时,如果此时我们执行了clearTimeout(20),那么由于其代表的test()正在执行,相当于什么也没有做。而紧接着的第3行代码注册了一个标识为21的待执行函数,而此时clearTimeout()已经执行过了,清理失败。因此为了保证当前的id永远代表下一个待执行函数的标识,应该将行3的代码提升至函数顶,如下:

var test = function() {
     id = setTimeout(test, 1000); //put at top to clear the next func
     //do something
 }

  此时只要test得到执行,id立刻更新为下一个函数的id。也就杜绝了清理失败的可能。

setTimeout setInterval 学习笔记

原文:http://www.cnblogs.com/defghy/p/3560895.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!