Vue2中Token续期定时器异常:页面切换不重置、提示仅触发一次
问题解决:Token续期定时器的修复方案
问题分析
原代码存在以下核心问题:
- 定时器作用域错误:
x和tokenTime在路由监听函数内定义,每次路由切换都会重新创建,无法正确复用和清除;且clearTimeout(tokenTime)属于错误用法——tokenTime是函数,并非定时器ID - 续期后未重启定时器:用户确认续期成功后,没有重新启动14分钟的提示定时器,导致后续不再触发续期询问
- 路由切换逻辑混乱:缺少统一的定时器管理机制,切换页面时未正确初始化新的定时器
- 倒计时实现错误:用
setTimeout实现倒计时只会执行一次,无法持续更新剩余时间
修复后的完整代码
export default { data() { return { isActive: false, active: 'main', activeSidebar: false, userId: '', // 存储定时器ID,实现统一管理 tokenRenewTimer: null, // 14分钟后触发续期提示的定时器 countdownTimer: null, // 15分钟自动登出的倒计时定时器 remainingTime: 900 // 15分钟=900秒 }; }, methods: { logout() { console.log('Logout'); this.clearAllTimers(); this.$store.dispatch('authLogout'); this.$store.commit('setLoginCheck', false); this.$router.push('/login'); }, // 清除所有定时器 clearAllTimers() { if (this.tokenRenewTimer) { clearTimeout(this.tokenRenewTimer); this.tokenRenewTimer = null; } if (this.countdownTimer) { clearInterval(this.countdownTimer); this.countdownTimer = null; } }, // 启动所有定时器 startTokenTimers() { this.clearAllTimers(); // 先清除旧定时器,避免重复触发 this.remainingTime = 900; // 重置倒计时 // 14分钟后显示续期提示(14*60*1000=840000毫秒) this.tokenRenewTimer = setTimeout(() => { this.showRenewPrompt(); }, 840000); // 启动15分钟自动登出的倒计时 this.countdownTimer = setInterval(() => { this.remainingTime--; const min = Math.floor(this.remainingTime / 60); const sec = this.remainingTime % 60; document.getElementById('demo').innerHTML = `${min}分${sec}秒`; // 时间到自动登出 if (this.remainingTime < 0) { this.clearAllTimers(); document.getElementById('demo').innerHTML = '已超时'; this.logout(); } }, 1000); }, // 显示Token续期提示 async showRenewPrompt() { // 先检查当前Token状态 await this.$store.dispatch('tokenCheck'); const tokenData = this.$store.getters.tokenData; if (tokenData === 'N' || !tokenData) { alert('Token已失效'); this.logout(); return; } const confirmRenew = confirm('是否要延长Token有效期?'); if (!confirmRenew) { alert('已取消Token续期'); this.logout(); return; } // 发起续期请求 await this.$store.dispatch('tokenCheck'); const newTokenData = this.$store.getters.tokenData; if (newTokenData === 'N' || !newTokenData) { alert('Token续期失败,已登出'); this.logout(); } else { alert('Token已成功续期'); // 续期成功后重启定时器,确保下一次14分钟后再次提示 this.startTokenTimers(); } } }, watch: { $route(to, from) { const loginCheck = this.$store.getters.loginCheck; const tokenData = this.$store.getters.tokenData; // 仅在登录状态且Token有效时启动定时器 if (loginCheck && tokenData && tokenData !== 'N') { this.startTokenTimers(); } else { this.clearAllTimers(); alert('无有效Token,将跳转至登录页'); this.logout(); } } }, // 页面初始化时启动定时器 mounted() { const loginCheck = this.$store.getters.loginCheck; const tokenData = this.$store.getters.tokenData; if (loginCheck && tokenData && tokenData !== 'N') { this.startTokenTimers(); } }, // 页面销毁时清除定时器,避免内存泄漏 beforeUnmount() { this.clearAllTimers(); } };
关键修复点说明
- 统一定时器管理:将定时器ID存储在组件
data中,跨方法实现清除与复用,解决作用域问题 - 逻辑拆分独立:把定时器启动、清除、续期提示拆分为单独方法,代码结构更清晰,便于维护
- 路由切换重置定时器:路由变化时先清除旧定时器,再启动新定时器,解决切换页面未初始化的问题
- 续期后重启定时器:用户确认续期成功后,调用
startTokenTimers()重新启动定时器,确保每14分钟触发一次续期提示 - 修复倒计时逻辑:用
setInterval实现持续倒计时,替代原代码错误的setTimeout单次执行逻辑 - 生命周期优化:在
mounted初始化定时器,beforeUnmount清除定时器,避免内存泄漏 - 异步逻辑优化:用
async/await处理Token检查请求,确保获取最新Token状态后再进行业务判断
内容的提问来源于stack exchange,提问作者user19395617
相关产品推荐
相关产品推荐

