1.为什么需要前端取消请求
- 场景1: 同一个位置的展示,A,B两个地方可以触发该请求,点击A后,接口pengding,此时点击了B,这个两个请求的返回时间是不定的,也就是说页面上可能先展示A的结果,过段时间B请求返回了又变成了B的结果,也可能顺序相反
- 场景2: 未管控重复点击,重复点击按钮查询
- 场景3:后端接口返回太慢,导致用户点击几次,后面返回时间不定,出现重复查询
2.取消请求的方案
let cancel
const CancelToken = axios.CancelToken
axios.post('/result', {}, res => {
resolve(res)
}, null, {
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
emulateJSON: false,
cancelToken: CancelToken && new CancelToken(function executor (c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c
})
}).catch(e => {
// 如果是cancel的,不进行错误处理
if (e.$error && axios.isCancel(e.$error)) {
return
}
reject(e)
})
// 取消请求
cancel && cancel()
3.上述取消方案存在的问题
- 场景1: 多个tab页,每个页面都会有相同的运行按钮,点击调用相同接口,如果用之前的方案,在tabB运行时,会取消掉tabA的运行,但需求是希望在当前tab只取消当前tab的请求,其他tab页的请求继续执行
4.改进方案
需要把每个请求给定唯一requestId,这样就可以定制化取消掉对应的请求。
此方案已经有个成熟的插件axios-cancel-plugin了
使用:
import axios from 'axios';
import axiosCancel from 'axios-cancel-plugin';
axiosCancel(axios, {
debug: false // default
});
axios.post('/result', {}, {
requestId: requestId
}).then(() => {
console.log('resolved post');
}).catch(thrown => {
if (axios.isCancel(thrown)) {
console.log('request cancelled post');
} else {
console.log('some other reason post');
}
});
axios.cancel(requestId); // 即可取消对应requestId的请求,当然也可传数组,一次取消多个请求