一、问题
1、在vue中使用setTimeout定时器的时候,可能会遇到关不掉的情况,会存在明明已经在beforeDestroy和destroyed中设置了定时器清除了,但是有时候没生效,定时器还会继续执行。
2、在这里需要说一下setTimeout的使用场景:
(1)需要执行一次定时的时候用得到,比如需要在多久之后执行的一次操作
(2)接口需要定时查询,并且需要在接口返回数据后再查询的情况下(接口定时查询的时候,该方式会经常用得到)
二、问题出现的原因
场景:目前有个接口方法,执行该方法需要5s执行完成,并且还需要在执行完后定时查询数据
问题原因分析:
(1)问题发生的场景
a. 该方法需要5s执行完,但是当执行到该方法中第2s的时候,切换页面的时候将该组件销毁了
b. 销毁了该组件,但是该方法还是会在缓存中执行往下执行,并不会因为组件销毁而停止执行后面的代码,所以后面的定时器还是会执行到,并且后续的定时器也会一直执行
c. 因为一直在缓存中执行,并且组件已经销毁了,所以定时器就会存在清不掉的情况
(2)这种情况是偶发性的,很少有需要执行5s的方法,为了将该问题复现测试,我测试的时候是自己模拟了一下这个场景,所以使用的是5s;大部分的情况可能是几十毫秒或者几百毫秒就可以执行完成了,但是在销毁的时候,恰好处于方法执行的过程中,就会导致定时器清不掉的情况
三、问题解决思路
1、解决的思路跟我之前写的关于定时器的使用及页面切换时定时器无法清除的问题解决办法这篇文章差不多,是基于该文章的思路的一个补充,可以一起参考下
2、在使用定时器的组件中,使用一个curPageUrl来记录当前使用组件的页面所在的路由地址
该参数是用于对比路由跳转的情况,如果该参数和当前访问的路由地址不一致,那么就能判断出使用定时器的组件已经销毁了,不需要再继续执行了
3、在created或mounted中为curPageUrl赋初始值
this.curPageUrl = this.$route.path;
4、在使用定时器的方法中判断是否往下执行
if (this.curPageUrl && this.curPageUrl != this.$route.path) {
return false;
}
5、在beforeDestroy和destroyed中为curPageUrl赋一个永远不能出现的一个值,并且清除定时器
this.curPageUrl = "end";
this.realtimeLoadPointDataTimer && clearTimeout(this.realtimeLoadPointDataTimer);
四、实现的源代码
export default {
data() {
return {
curPageUrl: "", // 当前页面的路由地址
};
},
watch: {},
created() {
this.query();
this.curPageUrl = this.$route.path;
},
mounted() {},
beforeDestroy() {
this.curPageUrl = "end";
this.realtimeLoadPointDataTimer &&
clearTimeout(this.realtimeLoadPointDataTimer);
},
destroyed() {
this.realtimeLoadPointDataTimer &&
clearTimeout(this.realtimeLoadPointDataTimer);
},
methods: {
/** 查询数据 */
query() {
this.realtimeLoadPointDataTimer &&
clearTimeout(this.realtimeLoadPointDataTimer);
if (this.curPageUrl && this.curPageUrl != this.$route.path) {
return false;
}
// 设置延迟5秒执行回调函数
setTimeout(() => {
if (this.checked == true) {
// 设置500毫秒执行一次
this.realtimeLoadPointDataTimer = setTimeout(() => {
this.query();
}, 500);
}
}, 5000);
},
},
};
五、总结
在开发过程中,定时器是会经常用得到的,这种情况发生的机率很小,但并不是不会发生,为了避免该情况发生,这一个解决方案可能并不是很完美,但是能够解决这类问题
如果有更好的解决方案,或者使用该解决方案解决类似问题的遇到了问题,欢迎即使交流!!!