最近在做项目中遇到了一个关于setInterval的问题。需求是能通过改变setInterval中的间隔时间,实现快进2倍、快进4倍 的功能,当快进速度超过4倍时,播放速度恢复到正常速度。可是但我点击三次过后,发现速度并没有恢复到正常速度,速度反而是更快了。一开始没多想,就在每次点击之后调用clearInterval(timer)方法,发现问题解决了,但是我并不知道为什么这样做能够解决这个问题。后来通过查阅关于setTimeout和setInterval的相关资料,写出了这篇文章,来跟大家一起探讨一下。
1、setTimeout(code,millisec)
| 参数 | 描述 |
|---|---|
| code | 要执行的代码 |
| millisec | 表示需要等待的时间,表示在millisec毫秒后将code加入到当前执行线程中 |
setTimeOut中的第一个参数(code)可以是字符串也可以是函数,但是字符串可能导致性能损失,所以最好是使用函数。且code只会被执行一次。调用cleartimeout()可以终止setTimeOut方法的执行。下面来看几个例子
document.getElementById("btn").onclick = function() {
var start = new Date().getTime();
setTimeout(function() {
console.log((new Date().getTime() - start) + "毫秒后开始执行setTimeout中的代码");
}, 1000);
test();
}
function test() {
var stime = new Date().getTime();
var content = ""
for(var i = 0; i < 5000000; i++) {
content = content + "34636";
}
var etime = new Date().getTime()
console.log("循环执行了" + (etime - stime) + "毫秒");
}
输出结果为:
document.getElementById("btn").onclick = function() {
var start = new Date().getTime();
setTimeout(function() {
console.log((new Date().getTime() - start) + "毫秒后开始执行setTimeout中的代码");
}, 500);
test();
}
function test() {
var stime = new Date().getTime();
var content = ""
for(var i = 0; i < 5000000; i++) {
content = content + "34636";
}
var etime = new Date().getTime()
console.log("循环执行了" + (etime - stime) + "毫秒");
}
输出结果为:
document.getElementById("btn").onclick = function() {
var start = new Date().getTime();
setTimeout(function() {
console.log((new Date().getTime() - start) + "毫秒后开始执行setTimeout中的代码");
}, 0);
test();
console.log("函数执行完毕")
}
function test() {
var stime = new Date().getTime();
var content = ""
for(var i = 0; i < 5000000; i++) {
content = content + "34636";
}
var etime = new Date().getTime()
console.log("循环执行了" + (etime - stime) + "毫秒");
}
输出结果为:
总结:从第三段代码,setTimeout中的第二个参数为0可以看出setTimeout总是在创建它的函数体运行完毕之后,才会去执行。setTimeout(fn,0)的含义就是不用再等多少秒了,只要主线程执行栈内的同步任务全部执行完成,栈为空就马上执行
如果需要取消超时调用的话,需要将setTimeout()赋值给某个变量,然后调用clearTimeout()方法,代码如下:
var timer = setTimeout(function() {
console.log("我是测试数据");
}, 0);
clearTimeout(timer);
2、setInterval(code,millisec)
| 参数 | 描述 |
|---|---|
| code | 要执行的代码 |
| millisec | 表示需要等待的时间,表示在millisec毫秒后将code加入到当前执行线程中 |
setInterval和setTimeOut的参数意义是一样的。只不过setTimeout中的code只会被执行一次,而setTimeout中的code会不断的被执行。调用clearInterval()可以终止setInterval方法的执行。这种重复定时器有两个问题:
- 某些间隔会被跳过;
- 多个定时器的代码执行之间的间隔可能比预期的要小。
3、serInterVal的原理分析
下面来看一个serInterVal的例子<button id="btn1">开始</button>
<script type="text/javascript">
window.onload=function(){
var i=1;
document.getElementById("btn").onclick=function(){
console.log("第"+(i++)+"此点击")
setInterval(function(){
console.log(new Date().getSeconds())
},1000)
}
}
</script>
输出结果如下:
结果分析:当我点击第一次时,setInterval中的函数体每1秒运行一次,当我点击第二次时,setInterval中的函数体每1/2秒运行一次,当我点击第三次时,setInterval中的函数体每1/3秒运行一次,当我点击第三次时,setInterval中的函数体每1/4秒运行一次。出现这样的原因是因为点击4次就调用了4次serInterval方法,相当于调用了4个定时器。用如下的图来进行分析能很好地解释为什么会出现上面情况的原因了。
结果分析:如上图所示,在0-1s内点击2次,在1-2s内点击第3次,在2-3内点击第4次,那么在第2秒内会调用两次setInterval中的函数体。在第3秒内会调用3次函数体,第4秒内会调用第4次函数体。
下面是验证过程: 代码如下:
<button id="btn1">开始</button>
<button id="btn2">结束</button>
<script type="text/javascript">
window.onload = function() {
var i = 1;
document.getElementById("btn1").onclick = function() {
console.log("第" + (i++) + "此点击")
var timer = setInterval(function() {
console.log(new Date().getSeconds())
}, 1000);
document.getElementById("btn2").onclick = function() {
console.log("点击结束按钮");
clearInterval(timer);
}
};
}
</script>
运行结果如下:
<button id="btn1">开始</button>
<button id="btn2">结束</button>
<script type="text/javascript">
window.onload = function() {
var i = 1;
var timer=null;
document.getElementById("btn1").onclick = function() {
if(timer){
clearInterval(timer);
}
console.log("第" + (i++) + "此点击");
timer = setInterval(function() {
console.log(new Date().getSeconds())
}, 1000);
};
document.getElementById("btn2").onclick = function() {
console.log("点击结束按钮");
clearInterval(timer);
}
}
</script>
先点击2次开始按钮,然后再点击结束按钮,操作输出结果如下:
点击快进按钮是播放速度快进2倍和快进4倍也就是把时间间隔设置成原来的1/2和1/4即可,但同时要调用clearInterval方法清除setInterval运行后返回的timer,这样才能达到预期的效果。