setTimeout
:超时调用;
setInterval
:间歇调用
调用时,代码是在全局环境中执行的,里面的this
在正常模式下指向window
,严格模式下指向undefined
。
参数:
- 第一个参数为字符串或者函数(建议使用函数,传递字符串可能导致性能损失)
- 第二个参数为以毫秒表示的时间,该时间表示多少毫秒后将当前任务加入任务队列。
注意:对于定时器,是准时添加的,但不是准时执行的。
返回值:
调用setTimeout和setInterval后会返回一个数值ID,可以用来取消定时器
取消:
clearTimeout(timeoutId)
、clearInterval(intervalid)
注意:取消超时调用的重要性远远高于间歇调用。因为间歇调用会一直执行,直到页面卸载。
两者的相同点
这两者都属于异步任务,由render进程下的定时器触发线程进行计数。
如:
setTimeout(function(){
console.log("Hello,lwf");
},1000);
当执行到如上代码时,首先上述代码除回调函数部分会进入任务栈,由js引擎线程(js内核)执行,发现是一个定时器(异步任务),由定时器触发线程开始计数。100ms后,将回调函数放入事件触发线程管理的任务队列中,继续等待,当执行栈和任务队列中前面代码都执行完毕后,将第一个参数表示的任务放入执行栈中开始执行,输出“Hello lwf”。(可以看出定时器是准时添加、不准时执行的)
两者的不同
本质上在于添加到任务队列的次数不同,setTimeout向任务队列中添加一次任务,setInterval间隔一定时间后就要向任务队列中添加一次任务。
使用setTimeout,而不使用setInterval,经常使用setTimeout来模拟setInterval
为什么?
使用setInterval的一些问题:
1). 累计效应(上面提到的),如果setInterval代码在(setInterval)再次添加到队列之前还没有完成执行,就会导致定时器代码连续运行好几次,而之间没有间隔。就算正常间隔执行,多个setInterval的代码执行时间可能会比预期小(因为代码执行需要一定时间)2). 譬如像iOS的webview,或者Safari等浏览器中都有一个特点,在滚动的时候是不执行JS的,如果使用了setInterval,会发现在滚动结束后会执行多次由于滚动不执行JS积攒回调,如果回调执行时间过长,就会非常容器造成卡顿问题和一些不可知的错误
扫描二维码关注公众号,回复: 1620591 查看本文章3). 把浏览器最小化显示等操作时,setInterval并不是不执行程序,它会把setInterval的回调函数放在队列中,等浏览器窗口再次打开时,一瞬间全部执行时
使用setTimeout模拟setInterval的例子
使用回调函数:
var num=0;
var max=10;
function incrementNumber(){
num++;
console.log(num);
if(num<max){
setTimeout(incrementNumber,500);
}else{
console.log("done");
}
}
incrementNumber();
- 使用setTimeout模拟setInterva和setInterval的不同
每次setTimeout计时到后,就会把任务加入任务队列。等待执行栈和任务队列前面的任务执行完后才能执行。之后再次遇到setTimeout,将任务再次加入任务队列。可以看出两次添加到任务队列的时间是不确定的,有误差(等待时间和执行时间)。setInterval每次都是精确地间隔一定时间,将任务加入任务队列。
定时器的应用
计时、指定时间内实现页面跳转、动画等
正向计时的例子,显示为 00:00:00 的形式:
var h=0;
var m=0;
var s=0;
var mysetInterval=setInterval(timer, 1000);
function timer(){
s++;
if(s>=60) {
s=0;
m++;
}
if(m>=60) {
m=0;
h++;
}
time.innerHTML=checkTime(h)+':'+checkTime(m)+':'+checkTime(s);
}
function checkTime(i){ //将0-9的数字前面加上0,例1变为01
return i<10 ? "0"+i:i;
}