产品性能提升的一小步(通过请求拦截与事件机制,解决网络请求重复问题)

123 阅读1分钟

问题

在我们日常开发中,会有重复发送同一个网络请求多次的情况,那么如何在不修改业务逻辑的前提下去优化,减少无用的网络请求呢?

解决方案

思路分析:

1.当第一次网络请求发出时,我们需要让其正常请求

2.在第一次网络请求还没有返回数据时,这个时候如果后续有重复请求发出,那么我们将其拦截掉不发送

3.将不发送的请求注册一个事件,当第一次的请求返回数据时,触发回调事件,也就是后续的重复请求将都使用第一次返回的数据

4.重复请求的定义:

请求链接相同并且请求参数相同



技术方案:

1.可以利用重写axios原型方法request来进行请求的拦截

2.可以利用事件总线eventBus进行后续重复请求的事件注册

3.等待第一次请求回来后,将后续注册的回调事件触发,返回数据



代码实现:

export function createHandleNoRepeat() {
  const urlObj = {
    value: {},
  };

  const eventBus = {
    cbArr: [],
    send(tag, responseData) {
      this.cbArr.forEach((item) => {
        if (item.tag === tag) {
          item.cb(responseData);
        }
      });
    },
    on(tag, cb) {
      this.cbArr.push({
        tag,
        cb,
      });
    },
    remove(tag) {
      this.cbArr = this.cbArr.filter((item) => {
        return item.tag !== tag;
      });
    },
  };

  function requestFromCache(tag) {
    return new Promise((resolve, reject) => {
      try {
        eventBus.on(tag, (responseData) => {
          resolve(responseData);
        });
      } catch (error) {
        reject(error);
      }
    });
  }

  const oldFun = axios.Axios.prototype.request;
  axios.Axios.prototype.request = function (...args) {
    const { url, data } = args[0];
    const tag = `${url}|${JSON.stringify(data)}`;
    if (urlObj.value[tag]) {
      return requestFromCache(tag);
    }
    urlObj.value = { ...urlObj.value, [tag]: true };
    return Reflect.apply(oldFun, this, args);
  };

  return {
    urlObj,
    handleResponse: function (resp, handleCb) {
      const tempResp = handleCb(resp);
      if (resp.config) {
        const { url, data } = resp.config;
        const tag = `${url}|${data}`;
        if (tempResp) {
          eventBus.send(tag, tempResp);
        } else {
          eventBus.send(tag, resp.data);
        }
        eventBus.remove(tag);
        delete urlObj.value[tag];
      }
      if (tempResp) {
        return tempResp;
      } else {
        return resp;
      }
    },
  };
}