一: 最简单:setInterval 轮询
<template>
页面内容
</template>
<script setup>
import { onMounted, onUnmounted } from 'vue'
import axios from 'axios'
let timer = null
const fetchData = async () => {
const res = await axios.get('/api/data')
console.log(res.data)
}
onMounted(() => {
fetchData() // 先请求一次
timer = setInterval(fetchData, 5000) // 每5秒轮询
})
onUnmounted(() => {
clearInterval(timer) // 组件销毁清除
})
</script>
<style src="./index.scss" lang="scss" scoped></style>
缺点:
1.如果接口慢,会请求堆积
2.可能同时发多个请求(还没返回又发新的)
二:推荐:setTimeout + 递归(更安全)
<template>
页面内容
</template>
<script setup>
import { onMounted, onUnmounted } from 'vue'
import axios from 'axios'
let timer = null
let isRunning = true
const loopFetch = async () => {
if (!isRunning) return
try {
const res = await axios.get('/api/data')
console.log(res.data)
} catch (e) {
console.error(e)
}
timer = setTimeout(loopFetch, 5000) // 等本次结束再发下一次
}
onMounted(() => {
loopFetch()
})
onUnmounted(() => {
isRunning = false
clearTimeout(timer)
})
</script>
<style src="./index.scss" lang="scss" scoped></style>
优点:不会并发
三:WebSocket(真正实时)
const ws = new WebSocket('ws://localhost:8080')
ws.onmessage = (event) => {
console.log('实时数据:', event.data)
}
优点:
1.服务端推送(不需要轮询)
2.真·实时
缺点:需要后端支持
Server-Sent Events(SSE)
const eventSource = new EventSource('/api/stream')
eventSource.onmessage = (event) => {
console.log(event.data)
}
如果是由vue3+vite的项目,可以使用下面方法
四:自己封装 usePolling
新建usePolling.js
// usePolling.js
import { ref, onUnmounted } from 'vue'
export function usePolling(fn, interval = 3000) {
const timer = ref(null)
const isRunning = ref(false)
const start = async () => {
if (isRunning.value) return
isRunning.value = true
const loop = async () => {
if (!isRunning.value) return
await fn()
timer.value = setTimeout(loop, interval)
}
loop()
}
const stop = () => {
isRunning.value = false
clearTimeout(timer.value)
}
onUnmounted(stop)
return {
start,
stop,
isRunning
}
}
调用usePolling.js
<template>
页面内容
</template>
<script setup>
import { usePolling } from '@/hooks/usePolling'
import axios from 'axios'
const fetchData = async () => {
const res = await axios.get('/api/data')
console.log(res.data)
}
const { start, stop } = usePolling(fetchData, 5000)
onMounted(() => {
start()
})
</script>
<style src="./index.scss" lang="scss" scoped></style>
优点:
1.自动避免并发
2.自动清理
3.可随时暂停/恢复
4.可复用
五:用 VueUse(强烈推荐 ⭐⭐⭐)
1.用 useIntervalFn(简单轮询)
Bash
npm install @vueuse/core
import { useIntervalFn } from '@vueuse/core'
import axios from 'axios'
const { pause, resume } = useIntervalFn(async () => {
const res = await axios.get('/api/data')
console.log(res.data)
}, 5000)
2.更推荐:useTimeoutFn(避免并发)
import { useTimeoutFn } from '@vueuse/core'
const loop = async () => {
await axios.get('/api/data')
start()
}
const { start, stop } = useTimeoutFn(loop, 5000)
VueUse优势:
1.自动处理生命周期
2.API 很优雅
3.和 Vue3 完全契合
4.内置暂停/恢复
六:用请求库 TanStack Query(Vue Query)
Bash
npm install @tanstack/vue-query
import { useQuery } from '@tanstack/vue-query'
import axios from 'axios'
const { data } = useQuery({
queryKey: ['data'],
queryFn: () => axios.get('/api/data'),
refetchInterval: 5000 // 自动轮询
})
优点(很强):
1.自动轮询
2.缓存
3.防抖
4.请求去重
5.错误重试
6.loading 状态