axios简单的请求防抖(全局统一处理)

4,501 阅读2分钟

1. 需求及引言

项目中用到axios作为HTTP请求库,为了考虑到性能与用户的体验,以及一些特殊情况(例如:数据量大导致响应时间慢,用户网速慢,用户双击等等),因此需要加上防抖来避免多次重复请求。

注:以下方法仅适用于全局控制所有接口防抖,并无法控制防抖的时间,仅能控制单个接口在未响应前无法重复发出请求

2. 解决方案

想要统一控制状态,就需要用到请求拦截器响应拦截器

先写工具函数

// axios 增加防抖

// 正在进行中的请求列表
let reqList = [];

/**
 * 阻止重复请求
 * @param {array} reqList - 请求缓存列表
 * @param {string} url - 当前请求地址
 */
const isRepeatRequest = (reqList, url) => {
    if (reqList.includes(url)) {
        return true;
    }
    return false;
};

// 请求成功删掉队列中的请求
const removeFinishedRequest = (reqList, url) => {
    reqList = reqList.filter(item => item !== url);
    return reqList;
};

// 生成用于对比的url  url + method + data + params
const getCheckRepeatRequestUrl = (url, method, data, params) => {
    return `${url}&&&${method}&&&${JSON.stringify(data)}&&&${JSON.stringify(params)}`;
};

axios请求和响应拦截器中,控制防抖

// 请求拦截器
service.interceptors.request.use(
    config => {
        // 这里我只是简单的做了 url 的单一识别
        if (!stopRepeatRequest(reqList, getCheckRepeatRequestUrl(service.$host + config.url, config.method, config.data, config.params))) {
            // 如果这个请求时重复的,就直接 reject
            return Promise.reject({
                repeatRequest: true
            });
        }
        // 将此次请求的 url 加入到请求队列中
        reqList.push(getCheckRepeatRequestUrl(service.$host + config.url, config.method, config.data, config.params));
        return config;
    },
    error => {
        // 请求失败时的code
    }
);
service.interceptors.response.use({
    //请求成功
    res => {
        // 请求成功后,将此次请求的 url 从队列中清除
        reqList = removeFinishedRequest(
            reqList,
            getCheckRepeatRequestUrl(res.config.url, res.config.method, res.config.data, res.config.params)
        );
        return res;
    },
    error => {
        // 如果 error 有 response 表示此接口有请求
        if (error.response) {
            // 就将此请求删除掉,因为接口会出现报错(401,500等等),这也算是请求了,并且不是重复请求
            // 所以在这里,错误的请求也要从队列中删除掉
            reqList = removeFinishedRequest(
                reqList,
                getCheckRepeatRequestUrl(
                    err.response.config.url,
                    err.response.config.method,
                    err.response.config.data,
                    err.response.config.params
                )
            );
        } else {
            // 没有 response 说明是我们手动 rejcet 掉的请求,就直接 return 就行了
            return error;
        }
    }
})

这样就实现了一个简单的请求防抖

3. 警告

  • 该方法只是一种非常简单的请求防抖方法,大型项目生产环境请勿随意使用。
  • axios官方提供了cancelToken的方式来拦截请求,大型复杂项目可以采用这种方式