【前端问题库】如何解决快速切换路由、Tab标签页导致的定时器关闭不了的问题

问题: [定时器] 如何解决快速切换路由、Tab标签页、以及切换等待缓存导致的定时器关闭不了的问题

问题现象分类

  1. setTimeoutsetInterval 的混用:

在我经历的项目中,一般都在混用,一般没有啥子问题,但是得明白setTimeout 实现定时查询 一般用于执行的方法中调用后台接口的情况,等接口请求完后,再执行下一次的接口调用; 使用setInterval的话,一般用于不调用后台接口的情况

  1. 快速切换路由、Tab标签页导致缓存调用接口和运行定时器:

要是用setInterval用来调用后端接口,可能会有问题,比如定时10s刷新,接口可能会15s才返回接口,还没等这次返回结果去刷新页面,就又去重新查询数据了,可能会造成数据混乱,频繁调用接口以及关闭不了定时器

  1. 死循环:

在使用setTimeout的时候,需要注意的问题就是不要写成死循环;再就是记得清除定时器,清除定时器用clearTimeout 方法

  1. 特殊情况(特定的组件、浏览器兼容、函数方法异常等):

在使用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

讨论

  1. 如何形成一套完整的解决方案
  2. 如何快速解决定时器问题,还是调用接口问题

解决方案一

很多网友的方案都很不错,特别是设立全局属性,放在全局来监听路由的变化与本页面组件的路有变化。

解决方案二
完整的逻辑与新颖的解法

  1. 在本组件设立一个开关 timer_handle,
  2. 接收destroyed() beforeDestroy()函数生产的离开组件、销毁组件的动作
  3. 识别调用函数时,是否生产定时器(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)
          }
      },

💞💖💓💗每个时代,
✨🌟⭐️💫都悄悄犒赏会学习的人。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
如果你使用了vue-router进行路由跳转,但是tab标签有跟着跳转,可能是因为你有为tab标签设置相应的路由。 一种解决方法是,为每个标签设置一个对应的路由,然后在路由跳转时,同时更新选中的标签。例如: ```javascript // 在路由配置中设置每个标签对应的路由 const routes = [ { path: '/home', component: Home, meta: { tab: 'home' } }, { path: '/about', component: About, meta: { tab: 'about' } }, { path: '/contact', component: Contact, meta: { tab: 'contact' } } ]; // 在页面中使用<router-view>来显示当前路由对应的组件 <template> <div> <div class="tabs"> <div :class="{ active: activeTab === 'home' }" @click="selectTab('home')">Home</div> <div :class="{ active: activeTab === 'about' }" @click="selectTab('about')">About</div> <div :class="{ active: activeTab === 'contact' }" @click="selectTab('contact')">Contact</div> </div> <router-view></router-view> </div> </template> <script> export default { data() { return { activeTab: 'home' }; }, methods: { selectTab(tab) { // 更新选中的标签 this.activeTab = tab; // 跳转到对应的路由 this.$router.push({ path: '/' + tab }); } }, watch: { // 监听路由变化,更新选中的标签 $route(to) { this.activeTab = to.meta.tab; } } }; </script> ``` 这样,在跳转路由时,标签也会跟着更新。如果你使用的是其他的标签组件库,也可以根据类似的原理进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

随风一样自由

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值