前言
须要勾销反复申请的场景:
- 比方输入框搜寻须要勾销上一次的反复申请
- tab 切换频繁获取数据列表接口时,接口反复申请
- 就是用户频繁切换操作时,咱们调用都是同一个接口的时候,就需要先勾销上一次的接口申请,只申请用户最初一次操作的接口,不然雷同的接口反复申请,接口是异步的,到时就容易拿到数据不是最初一次操作想要的数据了
axios 自身就封装了勾销事件
axios 中文文档 勾销事件
axios 勾销事件代码如下
- 办法一、能够应用 CancelToken.source 工厂办法创立 cancel token,像这样:
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/user/12345', {cancelToken: source.token}).catch(function(thrown) {if (axios.isCancel(thrown)) {console.log('Request canceled', thrown.message);
} else {// 处理错误}
});
axios.post('/user/12345', {name: 'new name'}, {cancelToken: source.token})
// 勾销申请(message 参数是可选的)source.cancel('Operation canceled by the user.');
- 办法二、还能够通过传递一个 executor 函数到 CancelToken 的构造函数来创立 cancel token:
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {cancelToken: new CancelToken(function executor(c) {
// executor 函数接管一个 cancel 函数作为参数
cancel = c;
})
});
// cancel the request
cancel();
独自应用 axios 的时候,两个办法都能够,然而封装好 axios 办法在 vue 中全局调用时,办法一有个问题,axios 的 cancel 办法会把行将要收回的申请勾销掉,所以用第二个办法
残缺 axios 封装代码如下:
import axios from 'axios'
import UserModel from '../models/user'
// 接口前缀
const PREFIX = {
mock: 'https://yapi.comliq.net/mock/31/', // yapi mock 地址
development: 'http://xxx/', // qa 环境
production: 'http://xxx/', // 生产环境
}
const env = process.env.NODE_ENV
let interfacePrefix = PREFIX[env] || PREFIX.production // 接口前缀
/**
* config 自定义配置项
* @param withoutCheck 不应用默认的接口状态校验,间接返回 response
* @param returnOrigin 是否返回整个 response 对象,为 false 只返回 response.data
* @param mock 是否应用 mock 服务
* @param timeout 接口申请超时工夫,默认 10 秒
* @param isCancelRequest 是否能够勾销申请
*/
const configDefault = {
returnOrigin: false,
withoutCheck: false,
mock: false,
timeout: 10000
}
// 创立申请器
const service = axios.create(Object.assign({
baseURL: '',
responseType: 'json',
headers: {'Content-Type': 'application/json;charset=utf-8',},
}, configDefault))
// 增加申请拦截器
service.interceptors.request.use(
request => {
const reqData = request.data || request.params
if (reqData && !request.canEmpty) { // 对申请参数进行解决,革除空参数
request.data = deleteEmpty(reqData)
}
// 检测接口,依据环境主动切换前缀
if (request.url.indexOf('http') === -1) {if (request.url[0] === '/') {request.url = request.url.substr(1)
}
request.url = `${env !== 'production' && request.mock ? PREFIX.mock : interfacePrefix}${request.url}`
}
// 若有做鉴权 token,须要申请头主动加上 token, 这个 token 本人封装获取的
request.headers.accessToken = UserModel.getToken()
return request
},
error => {return Promise.reject(error)
},
)
// object 对象寄存每次 new CancelToken 生成的办法
let source = {}
// 每次申请前都会把 path 放在此数组中,响应胜利后革除此申请 path
let requestList = []
// 定义勾销办法
function cancelRequest(path, allCancel) {
// 申请列表里存在此 path,即发动反复申请,把之前的申请勾销掉
if (path && requestList.includes(path) && typeof source[path] === 'function') {source[path]('终止申请')
} else if (!path && allCancel) {
// allCancel 为 true 则申请列表里的申请全副勾销
requestList.forEach(el => {source[el]('批量终止申请')
})
}
}
// 增加响应拦截器
service.interceptors.response.use(
res => {
// 获取申请的 api
const path = JSON.stringify(res.config.url)
// 申请实现后,将此申请从申请列表中移除
requestList = requestList.filter(item => !path.includes(item))
// HTTP 状态码 2xx 状态入口,data.code 为 200 示意数据正确,无任何谬误
},
error => { // 非 2xx 状态入口
return Promise.reject(error)
},
)
// 这里只做 post 封装演示,大家能够本人封装其余申请办法
function requestFn(method, path, params = {}, options = {}) {
// 勾销上一次申请
if (requestList.length) {cancelRequest(path)
}
// 设置 isCancelRequest 为 ture, 申请前将 path 推入 requestList
if (options.isCancelRequest) {requestList.push(path)
}
if (method === 'post') {
return service.post(path, params, {
cancelToken: new axios.CancelToken(c => {source[path] = c
}),
...options
})
}
}
export const api = {
axios: service, // 原始 axios 对象
// 从新封装 get 函数,对立应用形式
get: (path, data, config) => service.get(path, { params: data, ...config}),
delete: (path, data, config) => service.delete(path, { data, ...config}),
post: (path, data, config) => requestFn('post', path, data, config),
put: (path, data, config) => service.put(path, data, config),
}
export default api
参考文献:
Vue 中封装带有勾销申请的 axios