关于定时器setInterval()累加或者是重叠的问题
当给一个click事件添加定时器的时候,如果多次点击,而没有及时清除定时器,就会产生定时器累加的问题,具体表现为:调用函数的时间间隔越来越短,越来越快。在使用setInterval()时会返回一个定时器的id值。利用这个id值,使用clearInterval(id),就可以将id是这个值的定时器关闭掉。<button id="btn1">开始</button><but
当给一个click事件添加定时器的时候,如果多次点击,而没有及时清除定时器,就会产生定时器累加的问题,具体表现为:调用函数的时间间隔越来越短,越来越快。
在使用setInterval()时会返回一个定时器的id值。利用这个id值,使用clearInterval(id),就可以将id是这个值的定时器关闭掉。
<button id="btn1">开始</button>
<button id="btn2">停止</button>
<script type="text/javascript">
var int;
btn1=document.getElementById("btn1");
btn2=document.getElementById("btn2");
btn1.onclick=function(){
int=setInterval('console.log(2)',400);
}
btn2.onclick=function(){
clearInterval(int);
}
</script>
一旦点击开始,就会开始定时器,调用函数,然后点击关闭,就可以把这个定时器关闭掉。
但是如果多次点击这个开始按钮,打印2的速度就会越来越快,此时点击停止按钮,好像不起作用?但是实际上,是起了作用的,此时点击它,只是关闭了最新打开的那个定时器,而无法关闭在这之前多次打开的定时器。
也就是说,这样写,停止按钮仅仅是关闭最新打开的那个定时器,就算连续点击停止按钮也没有,因为:
clearInterval(int);
里面的int是全局变量,在每次点击开始按钮生成新的定时器时,都会被最新的定时器id赋值。于是里面存储的值就一直是最新的定时器id,所以多次点击关闭不能关闭全部定时器。
将代码改成:
<button id="btn1">开始</button>
<button id="btn2">停止</button>
<button id="btn3">打印最新一个定时器的id</button>
<script type="text/javascript">
var int;
btn1=document.getElementById("btn1");
btn2=document.getElementById("btn2");
btn3=document.getElementById("btn3");
btn1.onclick=function(){
int=setInterval('console.log(2)',400);
}
btn2.onclick=function(){
clearInterval(int);
}
btn3.onclick=function(){
alert(int);
}
</script>
尝试运行,当我只点击一下开始,就打印int中存储的定时器id,显示为2:
当我刷新后,点击两下开始按钮,再打印打印int中存储的定时器id,显示为3:
当我再次刷新后,点击三下开始按钮,再打印打印int中存储的定时器id,显示为4:
同样的,当我点击4次开始,id变成5;5次开始,id变成6……以此类推,也就是说,生成定时器时,其内存储的id值是整型数字,且按定时器生成的时间顺序,从2开始,一直到n。
如之前代码写的,int中存储的是最新的定时器id值,因为每生成一个新的定时器,int变量中存储的值就会被覆盖一次。
这样一来,就解释了为什么点击了多次开始按钮后,再点击关闭,就只能关闭最新生成的定时器的问题了。
有了这个猜想,我们还需要修改代码验证一下:
<button id="btn1">开始</button>
<button id="btn2">停止</button>
<!-- <button id="btn3">打印最新一个定时器的id</button> -->
<script type="text/javascript">
// var int;
btn1=document.getElementById("btn1");
btn2=document.getElementById("btn2");
// btn3=document.getElementById("btn3");
btn1.onclick=function(){
int=setInterval('console.log(2)',400);
}
btn2.onclick=function(){
clearInterval(2);
clearInterval(3);
clearInterval(4);
clearInterval(5);
}
// btn3.οnclick=function(){
// alert(int);
// }
</script>
既然定时器的id是数字,那么我们直接利用clearInterval()里面参数直接放数字,这里放2345,也就是说按之前的想法,我点击开始按钮4次,然后点击关闭,就会把这4个生成的定时器都关掉,不再打印:
结果确实是这样,也就是说之前的想法是正确的。
于是就可以利用这个强制关闭,太多的,自己也不知道id值的定时器了:
for(var i=0;i<100;i++){
clearInterval(i);
}
这种方式就可以一次性无差别关闭100个定时器。
但是接下来,我又发现了一个问题,当我按了四次开始,又按了关闭按钮之后,id值为2345的定时器已经被关闭了。但是我又点击了4次开始按钮之后,却发现关闭按钮失效了!!
这肯定和int中存储的id值有关系,为了验证想法,将代码修改为:
<button id="btn1">开始</button>
<button id="btn2">停止</button>
<button id="btn3">打印最新一个定时器的id</button>
<script type="text/javascript">
var int;
btn1=document.getElementById("btn1");
btn2=document.getElementById("btn2");
btn3=document.getElementById("btn3");
btn1.onclick=function(){
int=setInterval('console.log(2)',400);
console.log(int);
}
btn2.onclick=function(){
clearInterval(2);
clearInterval(3);
clearInterval(4);
clearInterval(5);
}
btn3.onclick=function(){
alert(int);
}
for(var i=0;i<100;i++){
clearInterval(i);
}
</script>
我先点击了四次开始,然后关闭四个定时器(图中1部分),然后再点击开始,发现定时器的id并没有从头开始排布,而是变成6,继续走下去了!!
所以先前:
for(var i=0;i<100;i++){
clearInterval(i);
}
其实关闭的仅仅是最开始定义的100个定时器。
结论:
1.每次创建一个定时器,就会返回一个属于这个定时器的唯一一个id值,且为整型数字,从2开始。
2.利用clearInterval(i);可以删除定时器,i对应要删除的定时器的id值,要删除哪个,就得找到它的id值。
3.删除定时器之后,再创建新的定时器,id并不会从头开始,而是顺延下去。
基于以上的三点认识,就可以知道解决定时器叠加的问题了:
我们定时器累加,无非是因为创建的旧定时器没有及时关闭,然后又创建了新的定时器,所以产生了累加效果。
反过来想,只要及时删除就可以,于是我们就可以在创建定时器的函数中加个判断,如果已经存在定时器,则先关闭旧定时器,再打开新定时器,这样一来,就能够保证只有最新的一个定时器在运行,而int中始终存储的恰好是最新的定时器id,这就可以避免叠加了!
<button id="btn1">开始</button>
<button id="btn2">停止</button>
<script type="text/javascript">
var int=null;
btn1=document.getElementById("btn1");
btn2=document.getElementById("btn2");
btn1.onclick=function(){
if(int!=null){
clearInterval(int);
}
//如果int里面有数值,那一定是存在最新的一个定时器
int=setInterval('console.log(2)',400);
}
btn2.onclick=function(){
clearInterval(int);
int=null;
}
</script>
值得注意的是,在上面的代码中,存储计时器的id值的int都是全局变量,所以它一直存储着最新创建的计时器的id值。
但是,如果我们把这段代码改写成:
btn1.onclick=function(){
var int=setInterval(function(){
console.log(int);
},400);
}
把int用var声明成局部变量后,每次执行定时器中的function时,机会把当前计时器对应的id值赋值给int,也就是这个id存储的又是当前运行的计时器了。
比如我点了两下开始,每隔400ms就是id为2的定时器起一下作用,id为3的定时器起一下作用.所以就间隔着打印出23232323232323的值了。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)