/**
|
* 请求管理器 - 用于管理页面切换时的请求和加载状态
|
*/
|
|
class RequestManager {
|
constructor() {
|
// 存储当前正在进行的请求
|
this.pendingRequests = new Map()
|
// 存储页面加载状态
|
this.loadingStates = new Map()
|
// 缓存数据
|
this.dataCache = new Map()
|
// 缓存过期时间(5分钟)
|
this.cacheExpireTime = 5 * 60 * 1000
|
// 防抖定时器
|
this.debounceTimers = new Map()
|
}
|
|
/**
|
* 防抖包装函数
|
* @param {string} key - 请求标识
|
* @param {Function} fn - 要执行的函数
|
* @param {number} delay - 延迟时间(毫秒)
|
*/
|
debounce(key, fn, delay = 300) {
|
// 清除之前的定时器
|
if (this.debounceTimers.has(key)) {
|
clearTimeout(this.debounceTimers.get(key))
|
}
|
|
return new Promise((resolve, reject) => {
|
const timer = setTimeout(async () => {
|
try {
|
const result = await fn()
|
resolve(result)
|
} catch (error) {
|
reject(error)
|
} finally {
|
this.debounceTimers.delete(key)
|
}
|
}, delay)
|
|
this.debounceTimers.set(key, timer)
|
})
|
}
|
|
/**
|
* 取消防抖
|
* @param {string} key - 请求标识
|
*/
|
cancelDebounce(key) {
|
if (this.debounceTimers.has(key)) {
|
clearTimeout(this.debounceTimers.get(key))
|
this.debounceTimers.delete(key)
|
}
|
}
|
|
/**
|
* 添加请求到管理器
|
* @param {string} key - 请求标识
|
* @param {Promise} request - 请求Promise
|
* @param {Object} options - 配置选项
|
*/
|
async addRequest(key, request, options = {}) {
|
const {
|
useCache = true,
|
cacheTime = this.cacheExpireTime,
|
forceRefresh = false
|
} = options
|
|
// 如果使用缓存且缓存未过期,直接返回缓存数据
|
if (useCache && !forceRefresh && this.hasValidCache(key)) {
|
console.log(`[RequestManager] 使用缓存数据: ${key}`)
|
return this.dataCache.get(key).data
|
}
|
|
// 如果已有相同的请求正在进行,返回已存在的Promise
|
if (this.pendingRequests.has(key)) {
|
console.log(`[RequestManager] 请求已在进行中,等待结果: ${key}`)
|
return this.pendingRequests.get(key)
|
}
|
|
// 设置加载状态
|
this.setLoadingState(key, true)
|
|
// 创建可取消的Promise
|
const requestPromise = this.createCancelablePromise(request, key)
|
|
// 存储请求
|
this.pendingRequests.set(key, requestPromise)
|
|
try {
|
const result = await requestPromise
|
|
// 缓存结果
|
if (useCache) {
|
this.dataCache.set(key, {
|
data: result,
|
timestamp: Date.now(),
|
expireTime: cacheTime
|
})
|
}
|
|
return result
|
} catch (error) {
|
// 如果是取消错误,不抛出
|
if (error.name === 'CancelError') {
|
console.log(`[RequestManager] 请求已取消: ${key}`)
|
return null
|
}
|
throw error
|
} finally {
|
// 清理
|
this.pendingRequests.delete(key)
|
this.setLoadingState(key, false)
|
}
|
}
|
|
/**
|
* 创建可取消的Promise
|
*/
|
createCancelablePromise(request, key) {
|
let cancel
|
|
const promise = new Promise((resolve, reject) => {
|
cancel = () => {
|
const error = new Error('Request canceled')
|
error.name = 'CancelError'
|
reject(error)
|
}
|
|
request.then(resolve).catch(reject)
|
})
|
|
promise.cancel = cancel
|
return promise
|
}
|
|
/**
|
* 取消请求
|
* @param {string} key - 请求标识
|
*/
|
cancelRequest(key) {
|
const request = this.pendingRequests.get(key)
|
if (request && typeof request.cancel === 'function') {
|
request.cancel()
|
this.pendingRequests.delete(key)
|
this.setLoadingState(key, false)
|
}
|
}
|
|
/**
|
* 取消所有请求
|
*/
|
cancelAllRequests() {
|
for (const [key, request] of this.pendingRequests) {
|
if (typeof request.cancel === 'function') {
|
request.cancel()
|
}
|
}
|
this.pendingRequests.clear()
|
this.loadingStates.clear()
|
}
|
|
/**
|
* 检查是否有有效缓存
|
*/
|
hasValidCache(key) {
|
const cache = this.dataCache.get(key)
|
if (!cache) return false
|
|
const now = Date.now()
|
const isValid = (now - cache.timestamp) < cache.expireTime
|
|
if (!isValid) {
|
this.dataCache.delete(key)
|
}
|
|
return isValid
|
}
|
|
/**
|
* 清除缓存
|
* @param {string} key - 缓存标识,不传则清除所有
|
*/
|
clearCache(key) {
|
if (key) {
|
this.dataCache.delete(key)
|
} else {
|
this.dataCache.clear()
|
}
|
}
|
|
/**
|
* 设置加载状态
|
*/
|
setLoadingState(key, isLoading) {
|
this.loadingStates.set(key, isLoading)
|
}
|
|
/**
|
* 获取加载状态
|
*/
|
isLoading(key) {
|
return this.loadingStates.get(key) || false
|
}
|
|
/**
|
* 清理指定页面的所有资源
|
*/
|
cleanupPage(pageName) {
|
// 取消该页面的所有请求
|
const keysToCancel = []
|
for (const key of this.pendingRequests.keys()) {
|
if (key.startsWith(pageName)) {
|
keysToCancel.push(key)
|
}
|
}
|
|
keysToCancel.forEach(key => {
|
this.cancelRequest(key)
|
this.cancelDebounce(key)
|
})
|
}
|
|
/**
|
* 获取实例(单例模式)
|
*/
|
static getInstance() {
|
if (!RequestManager.instance) {
|
RequestManager.instance = new RequestManager()
|
}
|
return RequestManager.instance
|
}
|
}
|
|
export const requestManager = RequestManager.getInstance()
|
export default RequestManager
|