使用setInterval遇到的陷阱

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)
    }

此时可以获取到每次值的变化。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Vue中使用setInterval函数时,需要注意一些事项。首先,在使用setInterval之前,需要在mounted生命周期钩子中声明定时器,具体的写法是: ``` mounted() { this.timer = setInterval(() => { // 要执行的函数 }, intervalTime); } ``` 其中,intervalTime是执行函数的时间间隔。 其次,在组件销毁之前,需要在destroyed生命周期钩子中清除定时器,以避免内存泄漏。具体的写法是: ``` destroyed() { clearInterval(this.timer); } ``` 这样可以确保定时器在组件销毁时被正确清除。 此外,为了避免this指向的问题,可以使用箭头函数或者将this赋值给一个变量,以确保作用域一致。例如,在定时器内部使用箭头函数的写法是: ``` mounted() { this.timer = setInterval(() => { // 要执行的函数,可以直接使用this }, intervalTime); } ``` 或者可以声明一个变量that指向Vue实例this,在定时器内部使用that来代替this,以保证作用域一致。 总结起来,使用setInterval时,需要在mounted中声明定时器,在destroyed中清除定时器,并注意作用域的问题。以上是关于Vue中使用setInterval的一些注意事项。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [vue中定时器setInterval使用](https://blog.csdn.net/weixin_43254676/article/details/90906020)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值