你的位置:首页 > Java教程

[Java教程]setInterval和setTimeout


setTimeout和setInterval的基本用法我们不谈,无非是1.指定延迟后调用函数,2.以指定周期调用函数

 

让我们想象一个意外情况,比如说下面的setInterval

setInterval(function(){
    func(i++);},100)




  

我们以每100毫秒调用一次func函数,如果func的执行时间少于100毫秒的话好办,在遇到下一个100毫秒前就能够执行完:

但如果func的执行时间大于100毫秒,该触发下一个func函数时之前的还没有执行完怎么办?(前提是你要知道javascript只有单线程,不存在同时执行致命一说,才会有这个问题)。答案如下图所示,那么第二个func会在队列(这里的队列是指event loop,在下文中会详细提到)中等待,直到第一个函数执行完

如果第一个函数的执行时间特别长,在执行的过程中本应触发了许多个func怎么办,那么所有这些应该触发的函数都会进入队列吗?

 

不,只要发现队列中有一个被执行的函数存在,那么其他的统统忽略。如下图,在第300毫秒和400毫秒处的回调都被抛弃,一旦第一个函数执行完后,接着执行队列中的第二个,即使这个函数已经“过时”很久了。

还有一点,虽然你在setInterval的里指定的周期是100毫秒,但它并不能保证两个函数之间调用的间隔一定是一百毫秒。在上面的情况中,如果队列中的第二个函数时在第450毫秒处结束的话,在第500毫秒时,它会继续执行下一轮func,也就是说这之间的间隔只有50毫秒,而非周期100毫秒

那如果我想保证每次执行的间隔应该怎么办?用setTimeout,比如下面的代码:

var i =1  var timer = setTimeout(function(){
    alert(i++)
    timer = setTimeout(arguments.callee,2000)},2000)




 setInterval的问题:

1. 某些间隔会被跳过

2.多个定时器的代码执行之间的间隔可能比预期要小

 所以常用setTimeout代替setInterval

setInterval(fn,time)//↓↓↓↓↓↓↓↓↓↓↓↓setTimeout(function(){  fn();  setTimeout(arguments.callee,time);},time);
这样每次函数执行的时候都会创建一个新的定时器,第二个setTimeout()调用使用了agrument.callee 来获取当前实行函数的引用,并设置另外一个新定时器。这样做可以保证在代码执行完成前不会有新的定时器插入,并且下一次定时器代码执行之前至少要间隔指定时间,避免连续运行。
callee
返回正被执行的 Function 对象,也就是所指定的 Function 对象的正文。
[function.]arguments.callee
可选项 function 参数是当前正在执行的 Function 对象的名称。
说明:callee 属性的初始值就是正被执行的 Function 对象。
callee 属性是 arguments 对象的一个成员,他表示对函数对象本身的引用,这有利于匿名函数的递归或确保函数的封装性,例如下边示例的递归计算1到n的自然数之和。而该属性仅当相关函数正在执行时才可用。更有需要注意的是callee拥有length属性,这个属性有时候用于验证还是比较好的。arguments.length是实参度,arguments.callee.length是形参长度,由此能够判断调用时形参长度是否和实参长度一致。

//callee能够打印其本身
function calleeDemo() {
  alert(arguments.callee);
}
//递归计算
var sum = function(n){
  if (n <= 0) return 1;
  else return n +arguments.callee(n - 1)
}
比较一般的递归函数:
var sum = function(n){
  if (1==n) return 1;
  else return n + sum (n-1);
}
调用时:alert(sum(100));
其中函数内部包含了对sum自身的引用,函数名仅仅是个变量名,在函数内部调用sum即相当于调用一个全局变量,不能很好的体现出是调用自身,这时使用callee会是个比较好的方法。