接口函数,解决重复请求和并发请求问题
分为前端版本和服务器版本
/*
缓存并发接口函数,解决重复请求和并发请求问题
id:唯一值
cacheSecond:缓存时间,单位秒
syncFunc:加载函数
*/
const _map = {}
const _startTimeMap = {}
const _idArr=[]
const _resArr=[]
const _timeArr=[]
let len=0
let lenMax=100
async function CacheRequest (syncFunc,id,cacheSecond=0) {
const now = Date.now()
const idx=_idArr.indexOf(id)
if (idx>-1) {
if(now<_timeArr[idx]){
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()
}
}
}
module.exports=CacheRequest
// function getUser () {
// console.log('只会请求一次')
// return new Promise(function (resolve){
// setTimeout(function (){
// resolve({name:'name'})
// },2000)
// })
//
// }
// //解决重复请求问题
// async function test1(){
// const user1=await CacheRequest(getUser,'xx123',3000)
// const user2=await CacheRequest(getUser,'xx123',3000)
// const user3=await CacheRequest(getUser,'xx123',3000)
// console.log('test1',user1,user2,user3)
// }
// test1()
// //解决并发请求问题
// async function test2(){
// CacheRequest(getUser,'xx123',).then(function (user){
// console.log('test2',user)
// })
// CacheRequest(getUser,'xx123',).then(function (user){
// console.log('test2',user)
// })
// CacheRequest(getUser,'xx123',).then(function (user){
// console.log('test2',user)
// })
// }
// test2()
服务器版本redis
/*
缓存并发接口函数,解决重复请求和并发请求问题
id:唯一值
cacheSecond:缓存时间,单位秒
syncFunc:加载函数
*/
const redis = require('redis')
const crypto = require("crypto");
const _map = {}
const _startTimeMap = {}
let lenMax=1000
const version='v1'
const _idCache={
idArr:[],
len:0,
}
let client;
function md5key(key) {
const content=version+key
if (content.length <= 32) return content
let md5 = crypto.createHash('md5')
md5.update(content)
return md5.digest('hex')
}
const serverCache={
interNum:0,
init:async function (){
if (client) return client
let clientOptions = {
url: `redis://127.0.0.1:6379`,
database: 9,
}
let _client = redis.createClient(clientOptions)
_client.on("error", function (error) {
console.error('redis:', error)
})
await _client.connect()
client=_client
const {value,time}=await this.get('_idCache')
if(value.idArr.length>lenMax){
const dArr=value.idArr.splice(lenMax)
dArr.forEach(async (key)=>{
await this.del(key)
})
}
Object.assign(_idCache,value)
return client
},
set:async function (key,value){
await client.set(md5key(key),JSON.stringify({ value, time:Date.now() }))
},
get:async function (key){
const data={}
try {
Object.assign(data,JSON.parse(await client.get(md5key(key))))
}catch (e){
console.error(e)
}
return data
},
del:async function (key){
await client.del(md5key(key))
},
setCache_idCache:async function(){
this.interNum++
await new Promise(cb => setTimeout(cb, 5000))
this.interNum--
if(this.interNum===0){
await this.set('_idCache',_idCache)
}
}
}
async function _CacheRequestRedis (syncFunc,id,cacheSecond=0) {
const now = Date.now()
const idx=_idCache.idArr.indexOf(id)
if (idx>-1) {
const md5Key=_idCache.idArr[idx]
const {value,time}=await serverCache.get(md5Key,cacheSecond)
//在有效时间
if(now<cacheSecond*1000+time){
return value
}else{
_idCache.idArr.splice(idx,1)
await serverCache.del(md5Key)
if(_idCache.len>0){
_idCache.len--
}else{
_idCache.len=lenMax-1
}
serverCache.setCache_idCache()
}
}
// 兼容并发加载的情况
if (!_map[id]) {
_map[id] = []
_startTimeMap[id] = now
const res = await syncFunc()
//缓存时间
if(cacheSecond>0){
if(_idCache.idArr[_idCache.len]){
await serverCache.del(_idCache.idArr[_idCache.len])
}
_idCache.idArr[_idCache.len]=id
const md5Key=id
await serverCache.set(md5Key,res)
_idCache.len++
if(_idCache.len>=lenMax){
_idCache.len=0
}
serverCache.setCache_idCache()
}
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()
}
}
}
let initCacheRequestRedis=false
async function CacheRequestRedis(syncFunc,id,cacheSecond=0){
if(!initCacheRequestRedis){
await _CacheRequestRedis(function (){
return serverCache.init()
},'initCacheRequestRedis')
initCacheRequestRedis=true
}
return _CacheRequestRedis(syncFunc,id,cacheSecond)
}
module.exports=CacheRequestRedis
// function getUser () {
// console.log('只会请求一次')
// return new Promise(function (resolve){
// setTimeout(function (){
// resolve({name:'name'})
// },2000)
// })
//
// }
// //解决重复请求问题
// async function test1(){
// const user1=await CacheRequestRedis(getUser,'xx123',3000)
// const user2=await CacheRequestRedis(getUser,'xx123',3000)
// const user3=await CacheRequestRedis(getUser,'xx123',3000)
// console.log('test1',user1,user2,user3)
// }
// test1()
// //解决并发请求问题
// async function test2(){
// CacheRequestRedis(getUser,'xx123',).then(function (user){
// console.log('test2',user)
// })
// CacheRequestRedis(getUser,'xx123',).then(function (user){
// console.log('test2',user)
// })
// CacheRequestRedis(getUser,'xx123',).then(function (user){
// console.log('test2',user)
// })
// }
// test2()

浙公网安备 33010602011771号