⚙️ Vue3 多任务轮询 Hook:优雅控制多接口定时刷新
·
在实际项目中,我们经常会遇到多个接口需要定时刷新的场景,比如:
-
实时监控面板:多个指标接口定时拉取
-
后台任务状态:周期检查任务执行情况
-
消息或通知中心:定时拉取新消息
如果每个接口都单独写一个 setInterval,不仅代码冗余,还容易造成内存泄漏、难以管理、互相干扰等问题。
本文带来一个可控性强、性能优雅的 Vue3 Hook —— useMultiPolling,用于统一管理多个轮询任务。
💡 功能特点
✅ 支持多任务独立启动/停止
✅ 支持异步任务(Promise)
✅ 自动在组件卸载时清理定时器
✅ 可随时动态扩展任务
✅ 支持局部或全局停止
🧩 Hook 实现
import { onUnmounted } from 'vue'
interface PollingTask {
name: string
callback: () => void | Promise<void>
interval: number
}
export function useMultiPolling(tasks: PollingTask[]) {
const timers = new Map<string, NodeJS.Timeout>()
const taskMap = new Map<string, PollingTask>()
// 初始化任务映射
for (const task of tasks) {
taskMap.set(task.name, task)
}
/** 启动任务(支持单个或全部) */
const startPolling = (taskName?: string) => {
const taskList = taskName ? [taskMap.get(taskName)] : tasks
for (const task of taskList) {
if (!task || timers.has(task.name)) continue
const run = async () => {
try {
await task.callback()
} finally {
const timer = setTimeout(run, task.interval)
timers.set(task.name, timer)
}
}
run()
}
}
/** 停止任务(支持单个或全部) */
const stopPolling = (taskName?: string) => {
if (taskName) {
const timer = timers.get(taskName)
if (timer) {
clearTimeout(timer)
timers.delete(taskName)
}
} else {
for (const timer of timers.values()) clearTimeout(timer)
timers.clear()
}
}
/** 组件卸载时自动清理 */
onUnmounted(stopPolling)
return { startPolling, stopPolling }
}
🧠 使用示例
<script setup lang="ts">
import { useMultiPolling } from '@/hooks/useMultiPolling'
const { startPolling, stopPolling } = useMultiPolling([
{
name: 'userStatus',
callback: async () => {
console.log('拉取用户状态...')
// await api.getUserStatus()
},
interval: 5000,
},
{
name: 'taskProgress',
callback: async () => {
console.log('检查任务进度...')
// await api.getTaskProgress()
},
interval: 3000,
},
])
onMounted(() => {
startPolling() // 启动所有任务
})
onUnmounted(() => {
stopPolling() // 组件卸载自动清理
})
</script>
⚙️ 进阶用法
1️⃣ 单独控制任务
startPolling('userStatus') // 仅启动用户状态轮询
stopPolling('taskProgress') // 暂停任务进度轮询
2️⃣ 动态添加任务
你可以在运行时更新任务列表:
tasks.push({
name: 'newData',
callback: () => fetch('/api/newData'),
interval: 8000,
})
🧩 优化点解析
| 优化点 | 说明 |
|---|---|
setTimeout + 递归 | 避免 setInterval 累积执行延迟 |
Promise 支持 | 可安全执行异步请求任务 |
Map 存储定时器 | 任务查找与清理效率高 |
| 自动销毁 | onUnmounted 防止组件卸载后继续执行 |
| 可单独启停 | 精细化控制每个任务状态 |
🪄 性能与扩展建议
-
若轮询任务较多且接口耗时大,可结合防抖节流或Web Worker进行进一步优化;
-
可结合 Pinia/Vuex 全局状态,在多组件间共享轮询结果;
-
若希望在页面切换或标签页不可见时暂停,可配合
visibilitychange事件使用。
🎬 总结
useMultiPolling 是一个轻量、灵活的 Vue3 Hook,
让你能以声明式方式管理多接口轮询,减少重复代码、提升可维护性。
更多推荐


所有评论(0)