通用组件-字典组件优化思路

字典组件接口优化

背景

在很多的PC端管理项目中,总会有很多字典的接口,对于重复字典接口,如果每一次都请求,会造成非必要的性能丢失。

思路

对于该痛点,我们能很快的想到复用接口请求的数据就好。而且一般像字典请求接口来说,请求参数简单固定化。对于这些接口,能实现map存储复用结果。

由于axios请求是个promise,只要第一次请求之后,将该promise存储起来,后续重复接口调用时都复用该接口。(promise的特性,状态一旦修改之后就不会被二次修改,永远都保持用一个值)

设计

javascript 复制代码
/**
 * 存放dict缓存的字段
 * 目前只针对页面级缓存,切换页面dictCacheMap会清空
 */
const dictCacheMap = new Map();
​
/**
 * 字典请求接口
 */
const dictUrl = [
  'dictDetail/list', // 获取字典,params: { dictName: String }
  'dictDetail/treeList', // 获取字典项树, parmas: { dictName: String }
];
​
/**
 * 判断是否命中缓存接口
 * @param {URL} url
 * @returns Boolean
 */
export const isDictUrl = url => {
  return dictUrl.some(dict => url.endsWith(dict));
};
​
/**
 * 判断是否已经缓存过字典
 * @param {String} dictName 请求的参数
 * @returns Boolean
 */
export const checkDictCache = dictName => {
  return dictCacheMap.has(dictName);
};
​
/**
 * 返回字典值
 * @param {String} dictName 请求的参数
 * @returns Promise
 */
export const getDictCache = dictName => {
  return dictCacheMap.get(dictName);
};
​
/**
 * 设置字典值
 * @param {String} dictName 请求的参数
 * @param {Promise} promise 请求promise
 * @returns Promise
 */
export const setDictCache = (dictName, promise) => {
  // 将请求的promise收集起来,重复的接口将该promise返回
  dictCacheMap.set(dictName, promise);
  return promise;
};
​
/**
 * 清除字典
 * @param  {...any} rest 清除的字典名,不输入默认清除全部
 */
export const clearDictCache = (...rest) => {
  if (rest.length === 0) {
    dictCacheMap.clear();
  } else {
    for (const v of rest) {
      dictCacheMap.delete(v);
    }
  }
};

在定义好数据存储的文件后,我们可对字典请求接口封装成组件,或是请求request拦截请求设置。在这里采用组件形式书写。

xml 复制代码
<!--
字典选择
-->
​
<template>
  <a-select     
    v-listening="$listening"
    v-bind="$attrs" 
    :value="dtValue" 
    :options="dictItems" 
 />
</template>
​
<script>
import {
  checkDictCache,
  getDictCache,
  setDictCache,
} from './dict-cache';
​
export default {
  props: {
    value: null, // 值
    dict: {
        type: String,
        default: ''
    }
  },
  data() {
    return {
      dtValue: this.value,
      dictItems: [], // 字典项
      url: {
        list: 'dict/list', // 平铺的字典项, params: { dictName: String }
      },
    };
  },
  computed: {
    // 请求配置
    requestOption() {
      const option = {
        method: 'post',
        params: {
          dictName: this.dict, // 请求的字典名
        },
      };
      return option;
    },
  },
  watch: {
    value(v) {
      this.dtValue = v;
    },
    // 请求配置变化后,触发一次接口调用
    requestOption() {
      this.fetchList();
    },
  },
  mounted() {
    this.fetchList();
  },
  methods: {
    fetchList() {
      // 是否命中字典缓存接口
      const fetchPromise = checkDictCache(this.dict)
        // 如果已经存在请求,复用之前请求的结果
        ? getDictCache(this.dict)
        // 如果不存在该请求,发送请求,并将请求promise复用起来
        : setDictCache(this.dict, this.fetchPromise());
      fetchPromise.then(res => {
        this.dictItems = res;
      });
    },
    // 发送请求
    fetchPromise() {
      return this.$$http(this.requestOption)
          .then(data => { 
            return data;
           });
    },
  },
};
</script>

对于字典请求接口缓存后,需要考虑删除缓存结果,一般来说我们针对页面级的缓存,当这个页面一直存在时,缓存就不会被清除。因此,清除缓存可以在路由的beforeEach钩子函数执行时主动清除缓存

javascript 复制代码
import { clearDictCache } from './dict-cache.js'
const router = createRouter({ ... })
​
router.beforeEach((to, from) => {
  clearDictCache()
  //
})

总结

接口缓存一种很常见的问题,很多方式都是采用map存储请求回来的 结果。但是在这种方式下会导致第一次数据还没请求到,到后续请求又需要该结果。因此,最好使用promise来兜底。promise对处理异步有着很多的优势!

相关推荐
一个专注写代码的程序媛1 小时前
vue组件间通信
前端·javascript·vue.js
一笑code1 小时前
美团社招一面
前端·javascript·vue.js
懒懒是个程序员2 小时前
layui时间范围
前端·javascript·layui
NoneCoder2 小时前
HTML响应式网页设计与跨平台适配
前端·html
凯哥19702 小时前
在 Uni-app 做的后台中使用 Howler.js 实现强大的音频播放功能
前端
烛阴2 小时前
面试必考!一招教你区分JavaScript静态函数和普通函数,快收藏!
前端·javascript
GetcharZp2 小时前
xterm.js 终端神器到底有多强?用了才知道!
前端·后端·go
JiangJiang2 小时前
🚀 React 弹窗还能这样写?手撸一个高质量 Modal 玩起来!
前端·javascript·react.js
吃炸鸡的前端2 小时前
el-transfer穿梭框数据量过大的解决方案
前端·javascript
高德开放平台2 小时前
文末有奖|高德MCP 2.0 出行领域首发打通大模型与高德地图APP互联
前端