一,问题
1、在vue中使用setTimeout定时器的时候,可能会遇到关不掉的情况,会存在明明已经在beforeDestroy和destroyed中设置了定时器清除了,但是有时候没生效,定时器还会继续执行。
2、在这里需要说一下setTimeout的使用场景:
(1)需要执行一次定时的时候用得到,比如需要在多久之后执行的一次操作
(2)接口需要定时查询,并且需要在接口返回数据后再查询的情况下(接口定时查询的时候,该方式会经常用得到)
二、问题出现的原因
场景:目前有个接口方法,执行该方法需要5s执行完成,并且还需要在执行完后定时查询数据
问题原因分析:
(1)问题发生的场景
a. 该方法需要5s执行完,但是当执行到该方法中第2s的时候,切换页面的时候将该组件销毁了
b. 销毁了该组件,但是该方法还是会在缓存中执行往下执行,并不会因为组件销毁而停止执行后面的代码,所以后面的定时器还是会执行到,并且后续的定时器也会一直执行
c. 因为一直在缓存中执行,并且组件已经销毁了,所以定时器就会存在清不掉的情况
(2)这种情况是偶发性的,很少有需要执行5s的方法,为了将该问题复现测试,我测试的时候是自己模拟了一下这个场景,所以使用的是5s;大部分的情况可能是几十毫秒或者几百毫秒就可以执行完成了,但是在销毁的时候,恰好处于方法执行的过程中,就会导致定时器清不掉的情况
重要就是在切换页面时 定时器并未清除掉(已经在VUE2,beforeDestroy,destroyed , VUE3 onBeforeUnmount,onUnmounted 中设置清除定时器方法但未生效)
解决方法
使用 路由 导航守卫 监听页面跳转时清除
VUE2 (无需引入 直接书写)
// destroyed() {
// clearInterval(this.timer); // 清除定时器
// }, 之前是这么写的
// 将 destroyed() 改为 beforeRouteLeave()
beforeRouteLeave(to, from, next) {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
this.$refs.mychild.headerClearTimeFn();
}
//注意一定要next()让其跳转!!!
next()
}
VUE3 需要引入
import { onBeforeRouteLeave } from 'vue-router'
onBeforeRouteLeave((to, from, next) => {
//清除定时器
// ......
next()
})
onBeforeRouteLeave(
离开当前页面路由时触,return false
则阻止跳转)
、onBeforeRouteUpdate(
路由更新时触发)
是vue-router
提供的两个composition api
,它们只能被用于setup
中。