一,setTimeout
和setInterval
介绍
1.很多人容易把setTimeout
和setInterval
理解成线程概念,其实不然,js
是单线程的,setTimeout
和setInterval
的计时虽然运行在浏览器内核的定时触发器线程上,但真正的回调函数依然被添加到事件队列,在js引擎线程中执行。
2.setTimeout
和setInterval
的作用简单来说就是将一些操作延时执行。
二,setTimeout
1.setTimeout(fn,[interval])
:用来指定某个函数或字符串在指定的毫秒数之后执行。该函数return
一个值,表示定时器编号。interval
的缺省值为0
。
2.HTML5
标准规定,setTimeout
的最短时间间隔是4ms
,当设置时间小于4ms
时都会自动调整成4ms
。
2.为了兼容IE9,可以使用IIFE
或者隐式调用向函数传递参数。
setTimeout((function(a,b){console.log(a+b)})(1,2),1000)
function add(a,b)
{
return a+b
}
setTimeout(function(){add(1,2)},1000)
三,setInterval
1.setInterval(fn,[interval])
:用来指定某个函数或字符串在指定的间隔内不停的执行。
{
setInterval(function(){console.log(a+b)},1000)
}
2.JavaScript
引擎规定:当使用setInterval()
时,仅当队列中没有该定时器的任何其他代码实例时,才将回调函数添加到队列中。这确保了定时器代码加入到队列中的最小时间间隔为指定间隔。而这将导致两个问题:
某些间隔被吞(如上面的定时器,当定时器加入队列到执行结束的时间大于1000ms时,下一个间隔就会被吞掉)
两个定时器执行的间隔小于规定的间隔(假设,某个定时器在950ms执行结束,而下一个定时器进来,事件队列刚好为空,主线程的同步任务又都执行结束,则下一个会立马执行,两个间隔只有50ms)
3.为了避免setIterval
的问题,我们可以使用链式的setTimeout
,或者递归setTimeout
setTimeout(function fn()
{ setTimeout(fn,interval);
},interval);
function fn()
{
// 定时器中要运行的代码
setTimeout(function(){fn()},interval)
}
四,clearTimeout
和clearInterval
1.我们可以使用clearTimeout
和clearInterval
来清除定时器,该函数的参数为定时器返回的编号。
let timer=setInterval(function(){console.log('1')},1000)
clearTimeout(timer)
五,注意事项
1.由于js的执行机制是事件循环机制,所以setTimeout
和setInterval
实际延迟运行的时间会大于等于我们设置的时间。
六,防抖和节流
1.防抖和节流都是通过定时器完成的
(10) 防抖:将某个动作推迟执行,若在期间内在此触发动作,则清空计时器重新开始计时
var timer=null
function fd(){
if(timer){
clearTimeout(timer)}
timer=setTimeout(function(){dosomething},500)}
(1)节流:某个动作在期间内只执行一次
var timer=null
function jl(){
if(timer){
return}
timer=setTimeout(function(){
dosomething;
clearTimeout(timer)},500)
}
六,牛客网例题
1.实现一个打点计时器,要求
从 start
到 end
(包含 start
和 end
),每隔 100 毫秒 console.log
一个数字,每次数字增幅为 1
返回的对象中需要包含一个 cancel
方法,用于停止定时操作
第一个数需要立即输出
当遇到这道题我一开始用了一个错误的方法:这种方法定时器在循环期间一口气创建,也就是每个定时器的开始计时的时间是几乎一样的,所以最后会一口气输出。
function count(start, end) {
console.log(start)
for(let i=1;i<=end-start;i++)
{
let count=setTimeout(()=>{
console.log(start+i)
},1000)
}
return {
cancel(){
clearTimeout(count)
}
}
}
若要用setTimeout
方法,正确的是使用递归。
function count(start, end) {
if(end>=start)
{
console.log(start)
start++
var counttime = setTimeout(()=>
{
count(start,end)
},100)
}
else{
clearTimeout(counttime)
}
return {
cancel(){
clearTimeout(counttime)
}
}
}
正如上面所说我们是使用setTimeout
递归来实现setInterval
,因此我们当然还可以使用setInterval
。
function count(start, end) {
console.log(start)
let counttime = setInterval(
()=>{
console.log(start+1)
start+=1
if(start===end){
clearInterval(counttime )
}
},100)
return {
cancel(){
clearInterval(counttime )
}
}
}