从一段问题程序窥探js定时器原理
大家先不要看后面的内容,先看下面这段简短的代码,想象i应该弹出的是多少呢?
var t=null; var i=0; function a(){ i++; if(i==20){ return; } t=setTimeout(a,17); } a(); alert(i);
这就是今天我写效果的时候遇到一个问题,当我设定一个定时器做循环的时候,下面的程序不等我的循环结束就开始运行了。
上段程序的答案是"1"。
那么为什么程序没等循环完毕就着急地开始运行alert(i)了呢,原因就出在setTimeout的原理上。
其实setTimeout和setInterval这两个定时器一旦触发,就是和js程序并行执行的,也就是他们并不在一个时间线上。计时器的作用是仅仅是做一个计划,那就是每隔一段时间执行一次目标方法。
比如我们做个周计划每周末都出去玩,这其实就是一个定时器,每隔七天出去玩一次。但是周一到周五还是要上班的,也就是说我们不能因为周末出去玩就周一到周五不干事了。
js程序也是这样的,计时器的任务我每到那个时间点会完成,但是其它时间我会继续执行下面的代码。如上程序,a函数运行到定时器前一句的时候,i的值是1,然后执行定时器,17毫秒远远大过程序的运行时间,于是js不等了继续执行,于是alert(i),也就是1。
为了证明计时器没有偷懒,我们每隔一段时间弹出一次i,如下程序:
var t=null; var f=null; var i=0; function a(){ i++; if(i==20){ return; } t=setTimeout(a,17); } function b(){ alert(i); f=setTimeout(b,17); } a(); b();
可以发现i的确是从0加到了20。
以上啰嗦总结成一句话,那就是定时器和js其他程序是并行执行的,互不影响!
于是开头的程序正确的写法应该是这样的:
var t=null; var i=0; function a(){ i++; if(i==20){ alert(i); return; } t=setTimeout(a,1); } a();
在程序出口的地方做操作,就可以正确地弹出i了(i=20)。