【前端小课堂】—— 如何取消一个ajax请求
这篇文章简单讨论一下,如何取消一个ajax请求。
一、取消ajax请求的场景
开发过程中,遇到需要取消ajax请求的场景有很多,例如:
- 请求超时,为了不影响用户体验,前端主动取消ajax请求;
- 页面转换,取消前一个页面尚未响应的ajax请求;
- 频繁发送请求的场景,取消前一个尚未响应的ajax请求,也就是所谓的防抖;
二、前端ajax请求的方式及终止取消
前端ajax请求是应用最频繁的操作。目前浏览器支持的ajax请求api主要有两种,XMLHttpRequest和Fetch API。除此之外,需要关注的就是第三方请求库了。最主要的包括jquery ajax和axios,前者在目前的前端开发模式中,已经很少使用了。所以,我们只讨论第三方请求库axios。
1、XMLHttpRequest请求的终止取消
XMLHttpRequest对象用于与服务器交互。通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。因而可以在不影响用户操作的情况下,更新页面的局部内容。
发送一个 HTTP 请求,需要创建一个XMLHttpRequest对象,打开一个 URL,最后发送请求。当所有这些事务完成后,该对象将会包含一些诸如响应主体或 HTTP status 的有用信息。
function onload () {
console.log(this.responseText)
}
const xhr = new XMLHttpRequest()
xhr.addEventListener("load", onload)
xhr.open('GET', 'http://127.0.0.1:4523/mock/797249/goods/list', true)
xhr.send()
取消终止该请求,需要用到XMLHttpRequest.abort() 方法。当一个请求被终止,它的readyState将被置为 XMLHttpRequest.UNSENT(0),并且请求的 status 置为 0。
setTimeout(() => {
xhr.abort()
}, 1000)
此时的readyState和status:
2、Fetch API请求的终止取消
Fetch API提供了一个JavaScript接口,用于访问和操作http请求协议,如请求和响应。并且还提供了一个全局异步获取资源的fetch()方法,不同于XMLHttpRequest,Fetch是基于Promise,使用更加简单,而且更合乎异步请求逻辑。并且还可以方便的service workers中使用。Fetch还集成了很多HTTP概念,例如:CORS,credentials和其他HTTP扩展等
fetch(`http://127.0.0.1:4523/mock/797249/goods/list?keyword=包包`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
body: ''
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
})
终止取消fetch请求,需要用到AbortController 和 AbortSignal
- 1、创建AbortController实例controller
- 2、使用 controller.signal属性,获取到AbortSignal实例signal
- 3、通过fetch方法的第二个参数选项signal,跟fetch请求关联
- 4、使用controller.abort()方法,终止取消fetch请求
const controller = new AbortController()
const signal = controller.signal
fetch(`http://127.0.0.1:4523/mock/797249/goods/list?keyword=包包`, {
signal,
// ...
})
// 终止取消
controller.abort()
结果会打印以下异常
Error: DOMException: The user aborted a request.
此时的signal状态
controller.abort()接受一个参数,作为终止请求的reason:
// 终止取消
controller.abort('请求超时')
此时的signal状态
3、axios请求的终止取消
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。在服务端它使用原生 node.js http
模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。
使用用例:
axios.get('http://127.0.0.1:4523/mock/797249/goods/list?keyword=包包')
.then(function (response) {
// 处理成功情况
console.log(response);
})
.catch(function (error) {
// 处理错误情况
console.log(error);
})
有两种方式可以终止取消axios请求:
- 从 v0.22.0 开始,Axios 支持以 fetch API 方式—— AbortController 取消请求
const controller = new AbortController()
axios.get('http://127.0.0.1:4523/mock/797249/goods/list?keyword=包包',{
signal: controller.signal
}).then(function (response) {
// 处理成功情况
console.log(response);
}).catch(function (error) {
// 处理错误情况
console.log(error);
})
// 取消请求
controller.abort()
- 使用 cancel token 取消一个请求,此 API 从
v0.22.0
开始已被弃用
const CancelToken = axios.CancelToken
const source = CancelToken.source()
axios.get('http://127.0.0.1:4523/mock/797249/goods/list?keyword=包包', {
cancelToken: source.token
}).catch(function (thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// 处理错误
}
})
source.cancel()
此时source如下列状态。
CancelToken原理基于cancelable promises proposal和XMLHttpRequest.abort,下面是主要源码:
class CancelToken {
constructor(executor) {
if (typeof executor !== 'function') {
throw new TypeError('executor must be a function.');
}
let resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
const token = this;
// ...
executor(function cancel(message, config, request) {
if (token.reason) {
// 已经被取消
return;
}
token.reason = new CanceledError(message, config, request);
// 对应上面this.promise的resolve
resolvePromise(token.reason);
});
}
//...
/**
* Subscribe to the cancel signal
*/
subscribe(listener) {
if (this.reason) {
listener(this.reason);
return;
}
if (this._listeners) {
this._listeners.push(listener);
} else {
this._listeners = [listener];
}
}
/**
* Returns an object that contains a new `CancelToken` and a function that, when called,
* cancels the `CancelToken`.
*/
static source() {
let cancel;
const token = new CancelToken(function executor(c) {
// 对应上面executor回调cancel,执行resolvePromise(token.reason)
cancel = c;
});
return {
token,
cancel
};
}
}
三、总结
总体来讲,浏览器支持的前端ajax请求,主要有两种XMLHttpRequest和 Request Api,对应的取消请求的方式也有两种:XMLHttpRequest.abort 和 AbortController.abort,记住即可!
转载自:https://juejin.cn/post/7243725358130331685