对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)
})
参考了网上的一些方法,如果有优化意见,欢迎指导。