使用场景
- tab 切换时刷新列表数据,如果使用的是同一个 dom 展示数据,当请求有延时,可能会导致两个 tab 数据错乱
- 导出文件或下载文件时,想中断导出或下载
注意事项
前端主动撤销请求依旧会触发服务端逻辑,会占用服务端资源,一般按钮触发的请求用限制点击来处理
具体使用
主要思路:使用变量存储当前状态为请求状态的请求,在请求拦截中收集请求并判断是否有已有相同的正在请求过程中的请求,在响应拦截中移除该请求保证变量中存储的请求状态都为请求中
1.定义变量和取消方法
const httpPending = [] // 用于存储每个ajax请求的取消函数和ajax标识
// 取消请求方法
const cancelHttp = (name, config = {}) => {
httpPending.forEach((e, i) => {
if (e.n === name || e.n === config.xhrName) {
// 当前请求在数组中存在时执行函数体
e.f("我撤销了请求") // 执行取消操作
httpPending.splice(i, 1) // 把这条记录从数组中移除
}
})
}
2.http 封装
export default class Http {
static async request(method, url, opts = {}) {
let params = {
xhrName: (opts && opts.name) || "",
method,
url: uri,
}
return axios(params)
}
static post(url, opts) {
return this.request("POST", url, opts)
}
}
3.请求拦截
axios.interceptors.request.use(
(config) => {
// 取消上一次未完成的相同请求,注意项目中是否存在风险
cancelHttp(null, config)
config.cancelToken = new CancelToken((c) => {
if (config.xhrName) {
httpPending.push({
n: config.xhrName,
u: `${config.url}&${config.method}`,
f: c,
})
}
})
return config
},
(error) => Promise.reject(error)
)
4.响应拦截
axios.interceptors.response.use((res) => {
cancelHttp(null, res.config) // 响应成功把已经完成的请求从 httpPending 中移除
})
5.通过 name 标识该请求是否能被撤销
export const httpRequest = (params) =>
Http.post("/api", { name: "httpRequest", body: params })
实现原理
1.首先明确
axios 是对 XMLHttpRequest 的封装,撤销请求时,最终使用 XMLHttpRequest 的 abort()方法
2.axios 内部实现
CancelToken 模块暴露了一个 promise 执行撤销的时候会执行这个 promise 的 resolve
function CancelToken(executor) {
if (typeof executor !== "function") {
throw new TypeError("executor must be a function.")
}
var resolvePromise
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve
})
var token = this
executor(function cancel(message) {
if (token.reason) {
// Cancellation has already been requested
return
}
token.reason = new Cancel(message)
resolvePromise(token.reason)
})
}
resolve 执行之后进入 then 里面的 function 执行最终的 abort()
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!request) {
return
}
request.abort()
reject(cancel)
// Clean up request
request = null
})
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!