问题: [定时器] 如何解决快速切换路由、Tab标签页、以及切换等待缓存导致的定时器关闭不了的问题
问题现象分类:
setTimeout
与setInterval
的混用:
在我经历的项目中,一般都在混用,一般没有啥子问题,但是得明白
setTimeout
实现定时查询 一般用于执行的方法中调用后台接口的情况,等接口请求完后,再执行下一次的接口调用; 使用setInterval
的话,一般用于不调用后台接口的情况
- 快速切换路由、Tab标签页导致缓存调用接口和运行定时器:
要是用
setInterval
用来调用后端接口,可能会有问题,比如定时10s刷新,接口可能会15s才返回接口,还没等这次返回结果去刷新页面,就又去重新查询数据了,可能会造成数据混乱,频繁调用接口以及关闭不了定时器
- 死循环:
在使用
setTimeout
的时候,需要注意的问题就是不要写成死循环;再就是记得清除定时器,清除定时器用clearTimeout
方法
- 特殊情况(特定的组件、浏览器兼容、函数方法异常等):
在使用Vue
Router路由跳转
或者keep-alive路径
的时候,会遇到路由切换的情况,有时候会出现定时器清除不掉的情况比如在首页中是用了定时器setTimeout
或者setInterval
,但是没有清除定时器,那么在访问同级目录页面的时候,首页页面的定时器还会执行,请求的接口也仍然会继续执行,所以要清除一下,在首页页面切换到同级目录页面的时候,会执行组件卸载的方法(componentWillUnmount)
,在该方法中调用清除定时器的方法(clearTimeout)
;
参考这位网友的方法(这里就不多赘述了):
https://blog.csdn.net/qq_28013889/article/details/125362886?ops_request_misc=&request_id=&biz_id=102&utm_term=%E9%A1%B5%E9%9D%A2%E5%BF%AB%E9%80%9F%E5%88%87%E6%8D%A2%20%E5%AE%9A%E6%97%B6%E5%99%A8%E7%AE%A1%E4%B8%8D%E4%BA%86&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-1-125362886.142v73wechat,201v4add_ask,239v1insert_chatgpt&spm=1018.2226.3001.4187
讨论:
- 如何形成一套完整的解决方案
- 如何快速解决定时器问题,还是调用接口问题
解决方案一:
很多网友的方案都很不错,特别是设立
全局属性
,放在全局来监听路由的变化与本页面组件的路有变化。
解决方案二:
完整的逻辑与新颖的解法
- 在本组件设立一个开关
timer_handle
,- 接收destroyed() beforeDestroy()函数生产的离开组件、销毁组件的动作
- 识别调用函数时,是否生产定时器(1. 第一个好处,避免全局属性的浪费,直接本组件监听;2. 第二个好处:开关利于组件的交流,3.第三个好处:既可以将定时器关闭,释放内存,又可以停止调用后台接口)
data() {
return {
loading: false,
timer: null,
timer_handle: false // 是否禁止定时器生产
}
},
created() {
this.getData();
},
destroyed() {
// 禁止定时器生产
this.timer_handle = true
// 页面关闭前关闭定时器 | 定时器清除
this.beforeCloseEvent();
},
beforeDestroy() {
// 禁止定时器生产
this.timer_handle = true
// 页面关闭前关闭定时器 | 定时器清除
this.beforeCloseEvent();
},
methods: {
/**
* 清除定时器 in
* 每次进入界面时,先清除之前的所有定时器,然后启动新的定时器
**/
clearTimer() {
window.clearInterval(this.timer);
this.timer = null;
this.setTimer()
},
/**
* 运行定时器
*/
setTimer() {
if (this.timer === null) {
this.timer = window.setInterval(() => {
this.getData();
}, 30000)
}
},
/**
* 清除定时器 out
* 每次离开当前界面时,清除定时器
*/
beforeCloseEvent() {
window.clearInterval(this.timer);
this.timer = null;
},
async getData() {
console.log('-----service---getData')
try {
// 控制定时器的生产
if (this.timer_handle) {
// window.clearInterval(this.timer);
// this.timer = null;
return false
}
// QoS策略
await this.getQosDataAll()
// 浮动IP模型
await this.getFloatingipsDataAll()
// 具体展示数据信息 demo
this.loading = false
// 定时器
this.clearTimer();
} catch (error) {
this.loading = false;
console.log(error)
}
},
`
运行定时器的其它写法:
this.$once('hook:beforeDestroy'
有箭头函数指向钩子函数,触发清除定时器
/**
* 运行定时器
*/
setTimer() {
if (this.progress_timer == null) {
this.progress_timer = setInterval(() => {
// 停止(直接停止、离开停止)
clearInterval(this.progress_timer);
this.$once('hook:beforeDestroy', () => {
clearInterval(this.progress_timer);
})
}, 2000)
}
},
💞💖💓💗每个时代,
✨🌟⭐️💫都悄悄犒赏会学习的人。