【Vue3】从混乱到有序:我用 1 个 Vue Hooks 搞定大屏项目所有定时任务

前言

你是否也曾在大屏项目中陷入这样的困境:

  • 为了实时展示数据,页面里塞了十几个setInterval
  • 定时器清理不当导致内存泄漏,页面越用越卡
  • 切换页面后轮询还在疯狂请求,控制台报错刷屏
  • 想统一控制所有定时任务的启停,却要逐个修改代码

作为一个常年和数据大屏打交道的前端开发者,我太懂这种痛了。大屏项目往往需要同时维护 N 个定时任务(数据刷新、状态同步、心跳检测...),原生定时器 API 用起来不仅繁琐,还容易出各种幺蛾子。

今天就给大家分享一个我专门为大屏场景设计的usePolling Hooks,用它管理定时任务,效率直接翻倍!

为什么需要专门的轮询 Hooks?

先说说大屏项目的特殊性:

  1. 高频定时任务多:一个大屏可能需要同时维护 5-10 个不同的轮询任务(实时数据、告警、状态更新等)
  2. 资源敏感:大屏通常需要长时间运行,内存泄漏是致命问题
  3. 可见性需求:页面隐藏时没必要继续轮询(比如切换标签页)
  4. 统一管理:需要能批量控制所有轮询的启停状态

原生setInterval的问题就很明显了:每次使用都要手动管理定时器 ID、手动清理、手动处理异常,代码冗余且容易出错。

于是我封装了这个usePolling Hooks,把所有重复逻辑收归一处,让业务代码只关注核心逻辑。

核心实现:usePolling.ts

先上代码,核心逻辑不到 50 行,却解决了大屏轮询的所有痛点:

js 复制代码
import { ref, onMounted, onUnmounted } from "vue";

// interval: 轮询间隔时间,默认5分钟
export function usePolling(fn: () => void, interval: number = 5 * 60 * 1000) {
  const timer = ref<number | null>(null);
  const isActive = ref(true); // 页面可见性控制
  const isPolling = ref(false);
  const startPolling = () => {
    if (isPolling.value) return; // 防止重复启动
    isPolling.value = true;
    if (timer.value) clearInterval(timer.value); // 清理旧定时器
    // 设置新定时器
    timer.value = window.setInterval(async () => {
      if (!isActive.value) return; // 页面不可见时不执行
      try {
        await fn(); // 执行轮询任务(支持异步)
      } catch (error) {
        console.error("轮询异常:", error); // 统一错误处理
      }
    }, interval);
    fn(); // 立即执行一次(大屏通常需要即时数据)
  };
  // 页面可见性变化时自动暂停/恢复
  const handleVisibilityChange = () => {
    isActive.value = !document.hidden;
  };
  // 组件挂载时启动轮询并监听可见性变化
  onMounted(() => {
    document.addEventListener("visibilitychange", handleVisibilityChange);
    startPolling();
  });
  // 组件卸载时清理资源
  onUnmounted(() => {
    if (timer.value !== null) {
      clearInterval(timer.value);
    }
    document.removeEventListener("visibilitychange", handleVisibilityChange);
  });
  return { startPolling };
}

大屏项目中的实战用法

使用起来更是简单到离谱,只需要两步:

  1. 定义你的轮询任务(比如请求数据)
  2. usePolling包装它,指定间隔时间
js 复制代码
<template>
  <div class="dashboard">
    <!-- 大屏内容 -->
  </div>
</template>

<script setup lang="ts">
import { usePolling } from "./hooks/usePolling";
import { fetchRealTimeData } from "./api/dashboard";

// 1. 定义轮询任务:获取实时数据并更新视图
const fetchData = async () => {
  const data = await fetchRealTimeData();
  // 更新组件状态...
};

// 2. 使用轮询Hooks:每30秒刷新一次
const { startPolling } = usePolling(fetchData, 30 * 1000);

// 如需手动控制(比如按钮触发重启)
// const handleRestart = () => {
//   startPolling();
// };
</script>

如果页面有多个轮询任务,直接多次调用即可:

js 复制代码
// 任务1:每30秒刷新实时数据 
usePolling(fetchRealTimeData, 30 * 1000);
// 任务2:每5分钟同步一次配置 
usePolling(syncConfig, 5 * 60 * 1000); 
// 任务3:每10秒检测一次告警状态
usePolling(checkAlarm, 10 * 1000);

所有轮询都会自动遵守页面可见性规则,组件卸载时自动清理,再也不用手动管理一堆定时器了!

总结

usePolling Hooks的不足以及需要完善之处,大佬们可以在评论区指出

相关推荐
零一科技2 小时前
Vue3拓展:实现原理 - 浅析
前端·vue.js
文心快码BaiduComate2 小时前
用文心快码写个「隐私优先」的本地会议助手
前端·后端·程序员
Cerrda2 小时前
Windows系统中使用fnm自动管理node版本
前端
samroom2 小时前
什么是MVVM以及HTML小案例
前端·html
mwq301232 小时前
《前端项目技术文档生成器》Prompt(可复用模板)
前端·llm·visual studio code
行云流水6263 小时前
uniapp h5图片长按隐藏默认菜单弹出
前端·javascript·uni-app
~无忧花开~3 小时前
JavaScript实现PDF本地预览技巧
开发语言·前端·javascript
一 乐4 小时前
宠物管理|宠物共享|基于Java+vue的宠物共享管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·springboot·宠物
小时前端4 小时前
“能说说事件循环吗?”—— 我从候选人回答中看到的浏览器与Node.js核心差异
前端·面试·浏览器