128 lines
3.1 KiB
TypeScript
128 lines
3.1 KiB
TypeScript
import { ref } from 'vue'
|
|
|
|
interface PendingRequest {
|
|
promise: Promise<any>
|
|
timestamp: number
|
|
}
|
|
|
|
// 请求去重超时时间
|
|
const REQUEST_DEDUP_TIMEOUT = 5000 // 5秒
|
|
|
|
export const useRequestDedup = () => {
|
|
// 正在进行的请求(用于去重)
|
|
const pendingRequests = new Map<string, PendingRequest>()
|
|
|
|
// 生成请求键
|
|
const generateRequestKey = (type: string, params?: Record<string, any>): string => {
|
|
if (!params || Object.keys(params).length === 0) {
|
|
return type
|
|
}
|
|
const sortedParams = Object.keys(params)
|
|
.sort()
|
|
.map((key) => `${key}=${params[key]}`)
|
|
.join('&')
|
|
return `${type}?${sortedParams}`
|
|
}
|
|
|
|
// 清理过期的请求
|
|
const cleanupPendingRequests = (): void => {
|
|
const now = Date.now()
|
|
const keysToDelete: string[] = []
|
|
|
|
pendingRequests.forEach((request, key) => {
|
|
if (now - request.timestamp > REQUEST_DEDUP_TIMEOUT) {
|
|
keysToDelete.push(key)
|
|
}
|
|
})
|
|
|
|
keysToDelete.forEach((key) => pendingRequests.delete(key))
|
|
}
|
|
|
|
// 带去重的请求函数
|
|
const dedupedRequest = async <T>(
|
|
type: string,
|
|
requestFn: () => Promise<T>,
|
|
params?: Record<string, any>,
|
|
force = false
|
|
): Promise<T> => {
|
|
const requestKey = generateRequestKey(type, params)
|
|
|
|
// 清理过期的请求
|
|
cleanupPendingRequests()
|
|
|
|
if (force) {
|
|
// 强制刷新时,如果有旧的请求正在进行,我们可以选择覆盖或者只是新开一个不存入 pending 的请求。
|
|
// 为保证拿到最新数据并避免干扰其他 pending 请求,我们直接执行并不保存到 pendingRequests。
|
|
return await requestFn()
|
|
}
|
|
|
|
// 检查是否有相同的请求正在进行
|
|
const pendingRequest = pendingRequests.get(requestKey)
|
|
if (pendingRequest) {
|
|
try {
|
|
return await pendingRequest.promise
|
|
} catch (error) {
|
|
// 如果请求失败,移除pending状态
|
|
pendingRequests.delete(requestKey)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
// 创建新的请求
|
|
const promise = requestFn()
|
|
pendingRequests.set(requestKey, {
|
|
promise,
|
|
timestamp: Date.now()
|
|
})
|
|
|
|
try {
|
|
const data = await promise
|
|
|
|
// 移除pending状态
|
|
pendingRequests.delete(requestKey)
|
|
|
|
return data
|
|
} catch (error) {
|
|
// 请求失败时移除pending状态
|
|
pendingRequests.delete(requestKey)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
// 清除所有pending请求
|
|
const clearAllPendingRequests = (): void => {
|
|
pendingRequests.clear()
|
|
}
|
|
|
|
// 获取pending请求统计
|
|
const getPendingStats = () => {
|
|
return {
|
|
totalPendingRequests: pendingRequests.size,
|
|
pendingByType: {} as Record<string, number>
|
|
}
|
|
}
|
|
|
|
return {
|
|
// 核心去重方法
|
|
dedupedRequest,
|
|
|
|
// 管理方法
|
|
clearAllPendingRequests,
|
|
cleanupPendingRequests,
|
|
|
|
// 工具方法
|
|
generateRequestKey,
|
|
getPendingStats
|
|
}
|
|
}
|
|
|
|
// 全局去重实例
|
|
let globalDedupInstance: ReturnType<typeof useRequestDedup> | null = null
|
|
|
|
export const getGlobalDedup = () => {
|
|
if (!globalDedupInstance) {
|
|
globalDedupInstance = useRequestDedup()
|
|
}
|
|
return globalDedupInstance
|
|
}
|