接口函数,解决重复请求和并发请求问题

 

 分为前端版本和服务器版本

/*
缓存并发接口函数,解决重复请求和并发请求问题
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()

  

  

  

posted @ 2024-08-27 00:12  无工时代  阅读(1)  评论(0编辑  收藏  举报