import { ref, onBeforeUnmount, Ref } from 'vue'
interface PollingResult {
isPolling: Ref<boolean>
startPolling: (pollInterval: number, totalTimeout: number, requestFn: () => Promise<void>) => void
stopPolling: (stopAll?: boolean) => void
}
export const usePolling = (): PollingResult => {
let lastPollingTimer: NodeJS.Timeout | null = null // 保存上一次的轮询定时器
let startTime: number | null = null
const isPolling = ref(false)
let timeoutTimer: NodeJS.Timeout | null = null // 声明超时定时器变量
const stopLastPolling = () => {
if (lastPollingTimer) {
clearTimeout(lastPollingTimer)
}
}
const stopPolling = (stopAll = false) => {
if (stopAll) {
stopLastPolling()
if (timeoutTimer) {
clearTimeout(timeoutTimer)
}
isPolling.value = false
} else {
stopLastPolling()
}
}
const startPolling = async (pollInterval: number, totalTimeout: number, requestFn: () => Promise<void>) => {
stopLastPolling()
const startTimestamp = Date.now()
startTime = startTimestamp
const poll = async () => {
if (startTimestamp !== startTime) {
// 如果startTime发生变化,则说明有新的轮询请求,当前轮询不执行
return
}
try {
await requestFn()
} catch (error) {
console.error(error)
} finally {
if (isPolling.value && startTimestamp === startTime) {
lastPollingTimer = setTimeout(poll, pollInterval)
}
}
}
isPolling.value = true
lastPollingTimer = setTimeout(poll, pollInterval)
if (totalTimeout > 0) {
timeoutTimer = setTimeout(() => {
stopPolling(true)
}, totalTimeout)
}
}
onBeforeUnmount(() => {
stopPolling(true)
})
return {
isPolling,
startPolling,
stopPolling,
}
}
+++
import { Ref, onBeforeUnmount, ref } from 'vue'
// eslint-disable-next-line
const sleep = (delay: number) => new Promise<void>((resolve) => {
setTimeout(() => {
resolve()
}, delay)
})
export const usePolling = (
polling: () => void,
delay: number,
): {
doPolling: (fn: () => Promise<void>) => Promise<void>
cancelPolling: (
) => void
loading: Ref<boolean>
} => {
const isPollingRef = ref(false)
const cancelPollingRef = ref()
const loading = ref(false)
const doPolling = async (fn: () => Promise<void>): Promise<void> => {
if (isPollingRef.value) {
return
}
isPollingRef.value = true
const pollNext = async () => {
// 如果掉了取消轮询,那么就返回不执行
if (cancelPollingRef.value) {
isPollingRef.value = false
cancelPollingRef.value = false
return
}
// 发送请求,返回值组装一下,给个 hasFinished 判断是否还要继续轮询
await polling()
await sleep(delay)
if (fn) {
await fn()
}
// 继续
await pollNext()
}
loading.value = true
await pollNext()
loading.value = false
}
const cancelPolling = () => {
if (isPollingRef.value) {
cancelPollingRef.value = true
}
}
onBeforeUnmount(() => {
cancelPolling()
})
return {
doPolling,
cancelPolling,
loading,
}
}