setInterval的使用
const interval = setInterval(() => {
console.log('执行一次')
if (...){
clearInterval(interval)
}
}, 2000)
常规使用方式如上,每隔2s执行一次,当条件成立时执行clearInterval(interval)阻断循环
解决setInterval的使用中不立即执行问题
使用setInterval是为了让某段程序定时循环执行,但是setInterval的执行机制是第一次不执行,间断设定的时间之后才执行。解决这个问题,最简单的方法就是在使用setInterval之前首先执行一次,但是这样的方式在代码简单时还好,循环的代码复杂时会带来代码冗余的问题,所以可以采用如下方式:
setInterval(function fun() {
console.log('执行')
return fun
}(), 3000)
在待执行的函数后面加一个小括号,表示立即执行一次,注意这样的用法需要在函数的末尾对函数本身进行返回。
解决使用setInterval异步执行时发送ajax请求带来的问题
setInterval是异步执行的,即:每一次的循环代码相互之间都是独立的,只会在设定的时间到达时立即执行,无论上一次的循环过程是否完成,这样在满足一些使用场景的时候就会带来问题。例如在进行ajax请求的时候,需要根据ajax请求的返回值判断是否继续循环,但是setInterval的每一次循环会直接无视返回值,继续向下执行。
假设场景如下:每隔1s访问如下接口‘/mocktemplate’(该接口每5s返回结果,模拟网络延迟返回结果慢的情况),根据返回的结果flag为true或者false判断是否进行下一次请求,如果使用setInterval,代码如下:
function cycle1() {
const inter = setInterval(() => {
console.log('执行了')
axios.post('/mocktemplate')
.then(res => {
if (res.data.flag) {
console.log(res.data.flag, 'res.data.flag')
clearInterval(inter)
}
console.log(res, '执行结果')
})
}, 1000)
}
执行结果如下:
我们需要的效果是返回true之后就停止循环,不再继续,但是由于循环设定是每1s执行一次,而接口返回的时间是5s,导致每一次的循环事件都无视结果按照每1s一次进入到执行队列中,6次循环事件都进入执行队列之后,第一次的ajax请求结果才返回,虽然为true,但还是要把之后的5次已经进入队列的事件执行完成。
所以如果要等待ajax的返回结果返回之后再进行下一次循环请求,就需要使用setTimeout代替setInterval,代码如下:
function cycle2() {
setTimeout(() => {
console.log('执行了')
axios.post('/mocktemplate')
.then(res => {
if (res.data.flag) {
console.log(res.data.flag, 'res.data.flag')
return res.data.flag
} else {
cycle2()
}
console.log(res, '执行结果')
})
}, 1000)
}
执行结果如下:
如图所示,在ajax返回true之前,不会进行向下执行,只是这样做得后果就是:循环执行的周期变成了“原循环周期+ajax请求返回的时间”
解决使用setInterval无限循环
1、需要无限循环的场景
一些使用场景,不希望循环停止,例如对网页进行每半小时刷新一次的操作,直接使用setInterval可以满足使用,但是因为setInterval不会自动清除定时器队列,每循环一次定时器都会叠加一次,无限长时间进行下去,最终会导致网页卡死。但是setTimeout是自带清除定时器的,配合setTimeout使用即可解决卡死的问题。用法如下:
setInterval(()=>{
setTimeout(()=>{
console.log('执行一次')
},0)
},2000)
2、跳转到其他页面时需要清除定时器
在react中使用定时器,用法如下:
useEffect(()=>{
const timer = setInetrval(()=>{
fun()
},5000)
return ()=>{
clearInterval(timer)
}
},[])
即在return里面清除定时器,页面销毁时会调用return的函数
3、实现选择不同的选项进入不同的循环(场景:一个下拉框,当选择不同任务时,触发onChange方法,在onChange方法中根据任务项拉取任务进度)
要解决对的问题:选择第一个任务,触发定时器任务,但是当定时器任务没有执行完毕的时候,再次选择其他的任务项,上一个定时器任务不会停止。可以使用useState对上一次的定时器进行保存。
const [interval,setInterval] = useState()
function onChange(name){
clearInterval(interval)
const timer = setInetrval(()=>{
getWorkFlow(name)
},5000)
setInterval(timer)
}
onChange函数刚进来的时候interval保存的仍然是上一次的定时器。
setInterval的闭包陷阱
setInterval和setTimeout无法获取到代码开始执行之后useState变化的值,例如:
const [flow, setFlow] = useState(null)
function cycle4(){
setInterval(()=>{
setFlow(true)
console.log(flow,'flow')
},2000)
}
cycle4开始执行之后,得到的flow的值始终是null,因为此时的上下文环境始终是程序开始执行之前的上下文环境,所以检测不到setFlow时flow的变化。
解决方法如下:使用useRef代替:
const flag1 = useRef()
function cycle4(){
setInterval(()=>{
flag1.current = true
console.log(flag1.current,'flag1.current')
},2000)
}
此时可以获取到每次值的变化。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)