/*
* 缓存并发接口函数,解决重复请求和并发请求问题
* id:唯一值
* cacheSecond:缓存时间,单位秒
* syncFunc:加载函数
* cacheMode:缓存模式,'default' 过期后重新拉取;'stale' 过期先用旧缓存返回、后台刷新(默认 'default')
*/
const _map = {}
const _startTimeMap = {}
const _idArr = []
const _resArr = []
const _timeArr = []
let len = 0
const lenMax = 3000
async function CacheRequest(syncFunc, id, cacheSecond = 0, cacheMode = 'default') {
const now = Date.now()
const idx = _idArr.indexOf(id)
if (idx > -1) {
// 在有效时间
if (now < _timeArr[idx]) {
return _resArr[idx]
} else if (cacheMode === 'stale') {
// 过期但启用"先用旧缓存、后台更新"模式:立即返回旧值,并触发一次后台刷新
_refreshCache(syncFunc, id, cacheSecond)
return _resArr[idx]
} else {
_idArr.splice(idx, 1)
_resArr.splice(idx, 1)
_timeArr.splice(idx, 1)
if (len > 0) {
len--
} else {
len = lenMax
}
}
}
// 兼容并发加载的情况
if (!_map[id]) {
_map[id] = []
_startTimeMap[id] = now
const res = await syncFunc()
// 缓存时间
if (cacheSecond > 0) {
_idArr[len] = id
_resArr[len] = res
_timeArr[len] = cacheSecond * 1000 + Date.now()
len++
if (len > lenMax) {
len = 0
}
}
setTimeout(function () {
if (_map[id].length > 0) {
_map[id].forEach(function (callback) {
callback(res)
})
}
delete _map[id]
delete _startTimeMap[id]
}, 0)
return res
} else {
// 10 秒超时后,并发不做优化
if (now - _startTimeMap[id] < 10000) {
return new Promise(function (resolve) {
_map[id].push(resolve)
})
} else {
return syncFunc()
}
}
}
/*
* 后台刷新缓存(cacheMode = 'stale' 模式专用)
* 成功:更新缓存内容和缓存时间;失败:保留旧缓存,等待下次请求重试
* 并发去重:同一 id 已有刷新进行中则跳过;超过 10 秒未完成允许重新触发
*/
function _refreshCache(syncFunc, id, cacheSecond) {
if (_map[id]) {
if (Date.now() - _startTimeMap[id] < 10000) {
return
}
// 上一次刷新挂起超过 10 秒,允许并发触发新的刷新
delete _map[id]
delete _startTimeMap[id]
}
const callbacks = []
_map[id] = callbacks
_startTimeMap[id] = Date.now()
;(async function () {
try {
const res = await syncFunc()
if (cacheSecond > 0) {
const idx = _idArr.indexOf(id)
if (idx > -1) {
// 更新已有缓存
_resArr[idx] = res
_timeArr[idx] = cacheSecond * 1000 + Date.now()
} else {
// 缓存槽已被覆盖/移除,重新写入
_idArr[len] = id
_resArr[len] = res
_timeArr[len] = cacheSecond * 1000 + Date.now()
len++
if (len > lenMax) {
len = 0
}
}
}
} catch (e) {
// 后台刷新失败:保留旧缓存,等待下次请求重试
} finally {
// 只清理自己发起的刷新,避免误删后续重新触发的刷新状态
if (_map[id] === callbacks) {
delete _map[id]
delete _startTimeMap[id]
}
}
})()
}
export default CacheRequest