接口函数,解决重复请求和并发请求问题
分为前端版本和服务器版本
/* 缓存并发接口函数,解决重复请求和并发请求问题 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()