setTimeout setInterval 学习笔记

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

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

1.
function test() {
    setTimeout(test, 10);
    //do something
}

2.  
function test(){...}
setInterval(test, 10);

 

 看起来效果一样,但是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()一直无法执行。这显然属于逻辑出了问题。

  实验:

 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);

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

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

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

 

clearTimeout 与 clearInterval

  两者根据func()的注册id来取消尚未执行的函数,动作是将其从q中移除。但是两者都无法阻止正在执行的func(),此时func()会正常执行到结束。

  javascript单线程执行,javascript没有线程机制,猜测其不存在并发(javascript中没有sleep()方法)。所有程序一旦运行无法终止,因此不需要考虑setTimeout()产生id的并发问题。

  如果javascript存在并发,应将func()内部setTimeout()函数提至最前。对于其单线程是否存在并发,存疑。

原文地址:https://www.cnblogs.com/defghy/p/3560895.html