这两个定时器在开发过程中经常使用,但是对于理论不太清楚,区别也一知半解,所以写个随笔学习记录一下。
W3C给出的解释
setTimeout:设置一个函数,在指定的延迟(毫秒)后被调用
setInterval: 在每次经过指定的持续时间后重复调用回调
个人理解两个的共同点就是设置延时执行,以下是自己试验写的代码:
console.log(1);
console.log(2);
setTimeout(() => {
console.log(3);
}, 100);
console.log(4);
console.log(5);
setInterval(() => {
console.log('this is interval test');
}, 3000);
// 1, 2, 4, 5, 3, this is interval test
可以看到设置了100ms和3000ms的代码块会被放在同步任务队列执行完之后再执行,其实本质是个异步处理,会把使用了setTimeout和setInterval的代码块滞后执行。需要特别注意的是,在W3C定义中有些许不明确的地方,“延迟后调用”并不代表到了延迟事件便马上调用。这两个定时器的本质都是在规定延时后插入代码块执行,不代表立刻执行,需要等正在执行中的函数或方法执行完毕。比如下面这个例子:
function func1(){
// 假设有一段非常复杂的代码,执行时间为 4s
console.log(2);
}
function func2(){
// 假设有一段非常复杂的代码,执行时间为 6s
console.log(3);
}
func1();
setTimeout(() => {
console.log(1);
}, 5000);
func2();
// 2, 3, 1
这个例子中,按顺序执行会先执行func1,用时4s,随后setTimeout告诉编译器,5s后我要执行打印1的代码,编译器接收开始计时后马上执行func2,但是func2需要执行6s,也就是说从func2开始执行的第5s已经到了定时器规定的延时,那编译器会怎么处理?把func2先停止再执行延时代码吗?不,func2已经在执行中,就要先执行完毕再执行延时代码,所以打印出来的是2,3,1
时间轴如下:
二者的区别
1.setTimeout只会执行一次,而setInterval会以等距时间多次执行,话不多说,上代码:
console.log(1);
setTimeout(() => {
console.log(2);
}, 100);
console.log(3);
setInterval(() => {
console.log('this is interval test');
}, 3000);
实行效果如下图所示:注意红圈位置是打印次数
2.setInterval的延时时间可能被跳过( 当T(延时代码块执行) >= T(设置延时) )
这个原因就比较有意思了,这是因为setTimeout和setInterval的计时起点不同导致的。
setTimeout如下:
function func1() {
/*
* 假设有一段代码块,执行时间为 2s
*/
setTimeout(() => {
console.log('test');
}, 1000);
}
func1();
执行时间轴如下:
setInterval如下:
function func2() {
/*
* 假设有一段代码块执行时间为2s
*/
setInterval(foo, 1000);
}
function foo() {
// 假设执行时间为 1.5s
}
执行时间轴如下:
因为foo还没执行完,设置的延时已经到了,所以下个foo进入等待,从效果上来看就是foo连续执行,其实只是foo的延时被执行时间覆盖了。