前端性能优化:前端接口缓存方案

功能概述:

  1. 前端项目中有同一接口重复触发的并发现象
  2. 一些公共数据接口,如用户信息,配置信息等接口需要多次获取
  3. 首页有大量重复请求影响启动时间

适用条件:

  1. 基本的公共数据和用户信息
  2. get类获取数据接口
  3. 基本原则就是缓存不更新或者更新周期较长的数据

大体思路:

  1. 初次请求时将接口promise缓存到map对象中,map中的key名使用api名+参数拼接;下一次请求到同一key名的接口直接返回缓存中的promise;如果没有此key的promise使用正常的接口请求;

需求功能:

  1. 同一个接口,需要区分参数进行存储接口名+参数,生成唯一字符串
  2. 支持异步接口请求
  3. 支持promise
  4. 考虑并发的情况,同一接口同时触发的情况
  5. 默认关闭缓存,通过接口参数设置单独开启缓存
  6. 支持设置有效期,过期主动清除,取代惰性删除可能引起的内存溢出

实现代码:

/****************** promise方案封装 **********************/
class ItemCache {
  constructor(promise, timeout) {
      // data可存返回数据,也可存promise
      this.promise = promise
      // 设定超时时间,设定为多少秒
      this.timeout = timeout
      // 创建对象时候的时间,大约设定为数据获得的时间
      this.cacheTime = (new Date()).getTime()
  }
}
class ExpriesCache {
  // 定义静态数据map来作为缓存池
  static cacheMap =  new Map()
  // 数据是否超时
  static isOverTime(name) {
      const promise = ExpriesCache.cacheMap.get(name)
      // 没有数据 判定超时
      if (!promise) return true
      // 获取系统当前时间戳
      const currentTime = (new Date()).getTime()        
      // 获取当前时间与存储时间的过去的秒数
      const overTime = (currentTime - promise.cacheTime) / 1000
      // 如果过去的秒数大于当前的超时时间,也返回null让其去服务端取数据
      if (Math.abs(overTime) > promise.timeout) {
          // 惰性清除过期数据
          ExpriesCache.cacheMap.delete(name)
          return true
      }
      // 不超时
      return false
  }
  // 当前data在 cache 中是否超时
  static has(name) {
      return !ExpriesCache.isOverTime(name)
  }
  // 删除 cache 中的 data
  static delete(name) {
      return ExpriesCache.cacheMap.delete(name) 
  }
  // 获取缓存
  static get(name) {
      const isDataOverTiem = ExpriesCache.isOverTime(name)
      console.log(isDataOverTiem)
      //如果 数据超时,返回null,但是没有超时,返回promise
      return isDataOverTiem ? null : ExpriesCache.cacheMap.get(name).promise
  }
  // 设置存储,默认过期时间600秒
  static set(name, promise, timeout = 600) {
      // 设置 itemCache
      const itemCache = new ItemCache(promise, timeout)
      // 缓存
      ExpriesCache.cacheMap.set(name, itemCache)
      // 定时器主动清除过期数据
      setTimeout(()=>{
        console.log('删除过期数据',name)
        ExpriesCache.delete(name)
      }, timeout*1000)
      console.log(ExpriesCache.cacheMap)
  }
  // 声明key接口名 name+参数拼接
  static getName(name,params) {
    const paramsUrl = tool.paramsUrl(params)
    const key = name + paramsUrl
    return key
  }
}

/****************** 缓存使用 **********************/
actions.forEach(item => {
  let name = item.name || item.action;
  api[name] = async params => {
    params = params || {}
    for (let i in params) {
      params[i] = params[i] != 0 ? params[i] || '' : params[i];
    }
    let result = await api.getopenid();
    let opendata = {
      openid: result["openid"],
      sign: result["sign"]
    }
    if (item.action === 'get_union_id' || item.action === 'wx_decode_data') {
      opendata["session_key"] = result['session_key'];
    }

    // 是否开启缓存,获取属性后删除该参数
    let isCache = params && params.isCache
    params && params.isCache && delete params.isCache

    // 生成key
    let key = ExpriesCache.getName(name,params);
    // 获得数据
    let promise = ExpriesCache.get(key)
    if(isCache && promise){
      // 返回缓存数据******
      console.log(key)
      return promise
    }else{
      // 正常请求接口流程
      const promise = new Promise((resolve, reject) => {
        http.request({
          url: item.url,
          data: {
            action: item.action,
            t: Date.now(),
            ...opendata,
            ...params,
          }
        }).then(res => {
          return resolve(res)
        }).catch(err => {
          hideLoading()
          return reject(err)
        })
      })
      // 设置promise缓存
      isCache && ExpriesCache.set(key, promise, 10,) 
      return promise
    }
  }
})

注:该方案借鉴了其他技术大佬的方案,因大家发的都一样,不知道原作者是谁,故无备注参考文章地址

你可能感兴趣的:(前端开发,小程序开发,前端,性能优化,缓存,小程序,javascript)