最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 如何实现前端请求优化-本地缓存数据

    正文概述 掘金(Daes)   2021-02-01   565

    前言?

    继上一篇实现防止重复网络,这添加一个本地缓存功能

    实现思路 ?

    如何实现前端请求优化-本地缓存数据

    判断接口是否有配置cache属性

    • 如果有cache属性,查看当前请求地址是否有

      • 没有数据正常发送请求
      • 本地有数据查看过期时间是否过期
        • 过期正常发送请求
        • 没有过期直接返回本地数据 Promise.resolve(data)
    • 没有cache属性

      • 正常发送请求

    一、配置请求接口 ?

    平时写请求接口api
    import { httpRequest } from '@/plugin/axios'; // axios.js 文件
    
    // 请求接口
    export function getInit(params) {
      return httpRequest({
        url: '/api/xxx/xxx',
        method: 'get',
        params,
        cache: {  //+ 在这里配置一个属性用于是否开启缓存
          m: 5,   // + 缓存 5分钟
          h: 1, // + 缓存1个小时
        }
      })
    }
    

    二、使用axios库文件进行配置 ?

    axios.js 配置文件
    import axios from 'axios';
    import { getRequest, HttpResponse, httpError } from './cacheHttp.js'; // 这里就是我们要实现的逻辑文件
    
    // 里面做一些请求拦截,响应拦截操作 具体查看axios文档
    const service = axios.create({
        baseURL: 'xxx/xxx',
    });
    
    // 请求拦截器
    service.interceptors.request.use(config => {}, error => {})
    
    // 响应拦截器
    service.interceptors.response.use(response => {
      HttpResponse(response); // + 2.响应请求回来执行
    }, error => {
      httpError(); // + 3. 错误处理
    })
    
    export function http(config) { // => 这里config就是传递的请求配置参数
        return getRequest(config, service); // + 1.在这里做一些逻辑操作
    }
    
    
    

    三、实现本地缓存配置文件 ?

    ?1.先封装一下localStorage文件

    localStorage.js 配置文件

    /**
     * 职责: localStorage 
    */
    
    // 存入localStorage
    export function setItemLocalStorage(key: string, data: any) {
      try {
        localStorage.setItem(key, JSON.stringify(data));
      } catch (e) {
        // (谷歌, 360, 火狐, ie)本地存储满了抛出的错误
        if (e.name === 'QuotaExceededError') {
          // 本地存储满了,清空本地存储
          removeItemStorage(key);
          localStorage.setItem(key, JSON.stringify(data));
        }
      }
    }
    
    // 获取localStorage
    export function getItemLocalStorage(key: string) {
      const res = localStorage.getItem(key);
      try {
        return JSON.parse(res);
      } catch (e) {
        throw new TypeError(`fail to get is ${key} localStorage, info ${e}`)
      }
    }
    
    // 删除localStorage
    export function removeItemStorage(key: string) {
      localStorage.removeItem(key);
    }
    
    // 清空所有localStorage
    export function clearLocalStorage() {
      localStorage.clear();
    }
    
    

    2.工具函数封装一下

    utils.js

    export const isObj = obj => Object.prototype.toString.call(obj) === '[object Object]' && Object.keys(obj).length > 0;
    
    export const isArray = arr  => Object.prototype.toString.call(arr) === '[object Array]' && arr.length > 0;
    
    export const CACHEKEY = 'CACHE_DATA'; // 存入本地数据的key
    
    /**
     * @param {Object} obj 
     */
    export const getformatObjVal = (obj) => {
      obj = typeof obj === 'string' ? JSON.parse(`${obj}`) : obj;
      let str = [];
      for (let p in obj) {
        if (obj.hasOwnProperty(p) && p !== '_t') {
          const item = obj[p] === null ? '' : obj[p]; // 处理null
          str.push(encodeURIComponent(p) + '=' + encodeURIComponent(item));
        }
      }
      return str.join('&');
    }
    
    export const getUrl = (config) => {
      // 暂时就在get请求、post请求的时候进行操作
      const { method = 'get', params = {}, url = '', baseURL = '' } = config;
      const urlVal: string = url.replace(baseURL, '');
      return `${urlVal}?${method === 'get' ? getformatObjVal(params) : 'post'}`;
    }
    
    
    

    3.下面我就可以开始写逻辑函数啦

    cacheHttp.js 配置文件

    (1)初步实现存入数据到本地localStorage

    /**
     * 职责: 缓存请求数据
    */
    import { getUrl, isObj, CACHEKEY } from '../utils';
    import { setItemLocalStorage, getItemLocalStorage } from '../utils/localStorage';
    
    export default class CacheRequet {
      getTime(time) {
        const { h = 0, m = 0 } = time;
        const _t = h * 3600 * 1000 + m * 60 * 1000; // 所有时间戳
        return _t + Date.now();
      }
    
      // 获取过期时间
      getExpirationTime(config) {
        const { cache } = config;
        if (isObj(cache)) {
          return this.getTime(cache);
        }
        if (typeof cache === 'boolean') {
          // 默认开启五分钟
          return this.getTime({ m: 5 });
        }
        return Date.now(); // 存入当前时间
      }
    
      setStorageData(data, config) {
        const urlKey = getUrl(config); // 获取url地址作为每一个key
        // 1.先取出所有的数据 然后在把当前的值塞入进去
        const mapData = getItemLocalStorage(CACHEKEY); // 本地所有数据
        if (!mapData) {
          const params = {};
          params[urlKey] = data;
          setItemLocalStorage(CACHEKEY, params); // 存入本地
          return;
        }
    
        mapData[urlKey] = data; // 赋值给当前对象
        setItemLocalStorage(CACHEKEY, mapData); // 存入本地
      }
    
      // 保存数据到本地
      setCacheData(response) {
        const { data, config } = response;
        const { cache } = config;
        if (!cache) return; // 不要开启缓存 直接返回
    
        this.setStorageData({
          data,
          expirationTime: this.getExpirationTime(config) // 过期时间
        }, config)
      }
    }
    
    const cacheRequst = new CacheRequet();
    // 响应请求
    export const HttpResponse = (response) => {
      cacheRequst.setCacheData(response); 
    };
    
    

    到这里我们就可以存入本地数据;?

    import { httpRequest } from '@/plugin/axios'; // axios.js 文件
    
    // 请求接口
    export function getInit(params) {
      return httpRequest({
        url: '/api/xxx/xxx',
        method: 'get',
        params,
        cache: {  //+ 在这里配置一个属性用于是否开启缓存
          m: 5,   // + 缓存 5分钟
        }
      })
    }
    

    本地缓存数据图:

    如何实现前端请求优化-本地缓存数据

    接下来继续实现如果获取本地数据并返回给页面。

    (2)实现获取本地数据

    导出接口 判断本地有没有缓存:

    getCacheData方法有值就返回本地缓存值,没有本地缓存返回false

    1.如果有值就直接拿去本地缓存的数据,返回一个成功的Promise.resolve

    2.本地没有缓存或过期时间过期,正常发送请求

    import cacheHttp from './cacheRequest/index';
    
    /**
     * @param {Function} http 请求体
     * @param {Object} options 打印控制台信息
     */
    export const getRequest = (http, options) => {
      return function (config) {
        const cacheData = cacheRequst.getCacheData(config);
        if (cacheData) {
          return Promise.resolve(cacheData); // 返回本地缓存数据
        }
        // 2.返回http方法
        return getHttp.getRequest(config); // 正常发送请求
      };
    }
    
    

    cacheRequest.js

    发送请求前先拦截请求,获取本地缓存数据,

    • 如果本地缓存有数据并过期时间没有过期,则返回本地数据
    • 没有本地数据直接发起新的请求
    /**
     * 职责: 缓存请求数据
    */
    import { getUrl, isObj, CACHEKEY } from '../utils';
    import { setItemLocalStorage, getItemLocalStorage } from '../utils/localStorage';
    
    export default class CacheRequet {
      constructor() {
        this.response = Object.create(null);
        this.config = Object.create(null);
      }
      
    	// ... 设置本地数据函数就省略
      
      
     // 获取本地缓存数据
      getCacheData(config) {
        const { cache } = config;
        if (!cache) return; // 不要开启缓存 直接返回
        const localData = getItemLocalStorage(CACHEKEY); //1. 获取本地所有数据
        if (!localData) return false; //2. 没有数据直接返回
        const urlKey = getUrl(config); // 获取url地址作为每一个key
       	console.log(localData); // 打印数据看看
      }
      
    }
    
    
    
    

    打印控制台看看本地缓存出来的数据:

    如何实现前端请求优化-本地缓存数据

    接下来就可以判断过期时间和当前时间进行比较:

     // 获取本地缓存数据
      getCacheData(config) {
        const { cache } = config;
        if (!cache) return; // 不要开启缓存 直接返回
        const localData = getItemLocalStorage(CACHEKEY); //1. 获取本地所有数据
        if (!localData) return false; //2. 没有数据直接返回
        const urlKey = getUrl(config); // 获取url地址作为每一个key
        // 3.判断当前数据是否过期
        const { data = {}, expirationTime = 0 } = localData[urlKey] || {};
    
        if (Date.now() >= expirationTime) {
          // 时间过期
          return false;
        }
    
        // 4.时间没有过期,返回本地数据
        return data
    
      }
    

    到这一步就实现了本地缓存功能啦?

    4.完整缓存文件代码

    cacheRequest.js

    /**
     * 职责: 缓存请求数据
    */
    import * as interFace from '../utils/interface';
    
    import { getUrl, isObj, CACHEKEY } from '../utils';
    import { setItemLocalStorage, getItemLocalStorage } from '../utils/localStorage';
    
    export default class CacheRequet {
      getTime(time) {
        const { h = 0, m = 0 } = time;
        const _t = h * 3600 * 1000 + m * 60 * 1000; // 所有时间戳
        return _t + Date.now();
      }
    
      // 获取过期时间
      getExpirationTime(config) {
        const { cache } = config;
        if (isObj(cache)) {
          return this.getTime(cache);
        }
        if (typeof cache === 'boolean') {
          // 默认开启五分钟
          return this.getTime({ m: 5 });
        }
        return Date.now(); // 存入当前时间
      }
    
      setStorageData(data, config) {
        const urlKey = getUrl(config); // 获取url地址作为每一个key
        // 1.先取出所有的数据 然后在把当前的值塞入进去
        const mapData = getItemLocalStorage(CACHEKEY); // 本地所有数据
        if (!mapData) {
          const params = {};
          params[urlKey] = data;
          setItemLocalStorage(CACHEKEY, params); // 存入本地
          return;
        }
    
        mapData[urlKey] = data; // 赋值给当前对象
        setItemLocalStorage(CACHEKEY, mapData); // 存入本地
      }
    
      // 保存数据到本地
      setCacheData(response) {
        const { data, config } = response;
        const { cache } = config;
        if (!cache) return; // 不要开启缓存 直接返回
    
        this.setStorageData({
          data,
          expirationTime: this.getExpirationTime(config) // 过期时间
        }, config)
      }
    
      // 获取本地缓存数据
      getCacheData(config) {
        const { cache } = config;
        if (!cache) return; // 不要开启缓存 直接返回
        const localData = getItemLocalStorage(CACHEKEY); //1. 获取本地所有数据
        if (!localData) return false; //2. 没有数据直接返回
        const urlKey = getUrl(config); // 获取url地址作为每一个key
        // 3.判断当前数据是否过期
        const { data = {}, expirationTime = 0 } = localData[urlKey] || {};
    
        if (expirationTime <= Date.now()) {
          // 时间过期
          return false;
        }
    
        // 4.时间没有过期,返回本地数据
        return data
      }
    }
    

    导出文件index.js

    import cacheHttp from './cacheRequest/index';
    
    const cacheRequst = new cacheHttp();
    
    /**
     * @param {Function} http 请求体
     * @param {Object} options 打印控制台信息
     */
    export const getRequest = (http: any, options?) => {
      return function (config) {
        const cacheData = cacheRequst.getCacheData(config);
        if (cacheData) {
          return Promise.resolve(cacheData); //1. 返回本地缓存数据 !!!
        }
        // 本地没有缓存数据 正常发送请求
        // 2.返回http方法
        return http(config);
      };
    }
    
    // 响应请求
    export const HttpResponse = (response) => {
      cacheRequst.setCacheData(response);
      return response;
    };
    

    这里我使用的axios库(按自己场景配置):

    axios.js

    import axios from 'axios';
    import { getRequest, HttpResponse, } from './cacheHttp.js'; // 这里就是我们要实现的逻辑文件
    
    // 里面做一些请求拦截,响应拦截操作 具体查看axios文档
    const service = axios.create({
        baseURL: 'xxx/xxx',
    });
    
    // 请求拦截器
    service.interceptors.request.use(config => {}, error => {})
    
    // 响应拦截器
    service.interceptors.response.use(response => {
       return  HttpResponse(response); // + 2.响应请求回来执行
    })
    
    export function http(config) { // => 这里config就是传递的请求配置参数
        return getRequest(config, service); // + 1.在这里做一些逻辑操作
    }
    
    
    

    以上就实现本地缓存啦。

    注意⚠️: 如果直接配置了一些响应拦截器相关,走本地缓存获取数据不会走响应拦截器,会直接返回本地缓存的数据。 后期可以可以加入一些配置。 后期在配置项加入一个回调函数解决。

    源码github

    可以直接导入项目使用。如果觉得我的思路有用的话不妨点个赞?。谢谢!

    如何实现前端请求优化-本地缓存数据


    起源地下载网 » 如何实现前端请求优化-本地缓存数据

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元