前言
你是否也曾在大屏项目中陷入这样的困境:
- 为了实时展示数据,页面里塞了十几个
setInterval - 定时器清理不当导致内存泄漏,页面越用越卡
- 切换页面后轮询还在疯狂请求,控制台报错刷屏
- 想统一控制所有定时任务的启停,却要逐个修改代码
作为一个常年和数据大屏打交道的前端开发者,我太懂这种痛了。大屏项目往往需要同时维护 N 个定时任务(数据刷新、状态同步、心跳检测...),原生定时器 API 用起来不仅繁琐,还容易出各种幺蛾子。
今天就给大家分享一个我专门为大屏场景设计的usePolling Hooks,用它管理定时任务,效率直接翻倍!
为什么需要专门的轮询 Hooks?
先说说大屏项目的特殊性:
- 高频定时任务多:一个大屏可能需要同时维护 5-10 个不同的轮询任务(实时数据、告警、状态更新等)
- 资源敏感:大屏通常需要长时间运行,内存泄漏是致命问题
- 可见性需求:页面隐藏时没必要继续轮询(比如切换标签页)
- 统一管理:需要能批量控制所有轮询的启停状态
原生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 };
}
大屏项目中的实战用法
使用起来更是简单到离谱,只需要两步:
- 定义你的轮询任务(比如请求数据)
- 用
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的不足以及需要完善之处,大佬们可以在评论区指出