axios的interceptors和cancelToken的具体实例

128 阅读2分钟

对axios进行封装:

  • 1.实现loading操作
  • 2.使用cancelToken避免多次请求
  • 3.使用promise封装post和get请求,使用拦截器interceptors添加loading

一.实现loading操作

在发起请求后,由于响应时间的不确定性,为提升用户体验,所以在发起请求后添加一个loading操作,请求成功后取消loading。

  • 使用element-ui的Loading组件
  • 以服务的方式调用loading
在loading.js 文件中

import { Loading } from 'element-ui';
/**
 * 每次请求开始调用startLoading,结束调用endLoading,
 * startLoading时reqNum+1,endLoading时reqNum-1
 * 当reqNum = 0 时,结束loading
 */
let reqNum = 0;
let loadingInstance = null;
function startLoading(){
    if(reqNum === 0){
        // 开始loading
        // 以服务的方式调用的全屏 Loading 是单例的:若在前一个全屏 Loading 关闭前再次调用全屏 Loading,并不会创建一个新的 Loading 实例
        loadingInstance = Loading.service({ fullscreen: true });
    };
    reqNum++;
}
function endLoading(){
    // 加了个延时,可以看到一个加载的过程
    setTimeout(function(){
        if(reqNum < 0) return;
        reqNum--;
        if(loadingInstance && reqNum === 0){
            // 结束loading
            loadingInstance.close();
        }
    },500)
}
export default {startLoading,endLoading}

二.使用cancelToken避免多次请求

请求的时间具有不确定性,为了避免同一个请求请求多次,所以晚发起的请求取消之前发起的请求

在cancel.js文件中

import axios from 'axios';
import { Message } from 'element-ui';

let pendings = {};
// 添加请求
const addPending = config => {
    const {url,methods,data,headers} = config;
    const id = [url,methods,JSON.stringify(data),JSON.stringify(headers)].join('&');
    const cancel = pendings[id];
    config.cancelToken = config.cancelToken || new axios.CancelToken(c => {
        if(!cancel){
            // 不存在,就存进去
            pendings[id] = c;
        }
    }) 
    return config;
}
// 删除请求
const removePending = config => {
    const {url,methods,data,headers} = config;
    const id = [url,methods,JSON.stringify(data),JSON.stringify(headers)].join('&');
    const cancel = pendings[id];
    if(cancel && typeof cancel == 'function'){
        // 存在这个请求,删除
        cancel();
        delete pendings[id];
        Message.error({
           message:'请求频繁,加载中'
        })
    }
}
// 清除所有请求
const clearPendings = () => {
    Object.keys(pendings).forEach(i = pendings[i]())
}
export default{ addPending,removePending,clearPendings}

三.使用promise封装post和get请求,使用拦截器interceptors添加loading

在http.js文件中

import axios from 'axios';
import store from '../../store'
// 引入之前写的两个文件
import Cancel from './cancel'
import Loading from './loading'
import { Message } from 'element-ui';

// promise封装get请求
const get = (url,params = {}) => {
    const token = store.state.userInfo ? store.state.userInfo.token : null;
    return new Promise((resolve,reject) => {
        axios({
            url,
            headers:{
                "authorization": token
            },
            params,
        }).then(res => {
            resolve(res)
        }).catch(err => {
            reject(err)
        })
    })
}
// 拦截器interceptor
// 请求拦截器
axios.interceptors.request.use(config => {
    // 只想在发起登录请求的时候有加载的效果
    if(config.url == '/api/userlogin'){
        Loading.startLoading();
    }
    Cancel.removePending(config);
    let config1 = Pendings.addPending(config);
    return config1;
},error => {
    return Promise.reject(error);
})
// 响应拦截器
axios.interceptors.response.use(response => {
    endLoading();
    return {
        data:response.data
    }
},error => {
    let text = JSON.parse(JSON.stringify(error)).response.status === 404
            ? '404'
            : '网络异常,请重试';
        Message.error({
            message:text
        })
     return Promise.reject(error)
})

aammnJ.jpg

参考了网上的一些方法,如果有优化意见,欢迎指导。