前言:
我们日常开发中,经常会遇到点击一个按钮或者进行搜索时,请求接口的需求。
如果我们不做优化,连续点击按钮或者进行搜索,接口会重复请求。
以axios为例,我们一般以下面几种方法为主:
1.使用防抖、节流函数限制请求操作(老传统,但是已经不是最佳实践了)
2.自定义节流阀(比如自定义一个字段loading,请求前值是true,请求后改为false。如果为值true,就终止往下请求,体验感很不友好,因为我们搜索的时候,会经常更换文字,所以上一个请求没结束,下个就没法请求。不推荐)
const getList = () => {
if(loading.value) return
loading.value = true
axios.get('/user/12345')
.then(res=> {
loading.value = fasle
})
}
3.使用axios请求库提供的api来解决重复请求的问题, AbortController或者CancelToken
Tips:有些请求库已经内置了这一功能,比如alova.js,有些之前同事的公司已经在运用,听说效果很不错,也很轻便,不需要配置便能过滤重复请求。但是目前我们大部分公司还是以axios为主的,所以我们下面主要分享下在axios里怎么完成这一功能。( 对alova感兴趣的伙伴,可以移步至官网了解下Alova.JS - 轻量级请求策略库 | Alova.JS)
AbortController
从v0.22.0开始,`Axios`支持`AbortController`以获取API的方式取消请求。具体如下:
const controller = new AbortController();
axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {
//...
});
// 取消请求
controller.abort()
示例:
<template>
<div>
<button @click="fetchData">请求</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
import axios from 'axios';
let controller = null;
function fetchData() {
if (controller) {
controller.abort();
controller = null;
}
controller = new AbortController();
axios.get('https://api/user/12345',{signal: controller.signal})
.then(response => {
...
})
}
</script>
效果如下图:可以看到,重复的请求会直接被终止掉!
axios.CancelToken
deprecated
此 API 从 v0.22.0
开始已被弃用,不应在新项目中使用。
CancelToken官网示例
官网使用方法传送门:取消请求 | Axios中文文档 | Axios中文网
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.');
示例:
<template>
<div>
<button @click="fetchData">请求</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
import axios from 'axios';
let cancelTokenSource = null;
function fetchData() {
if (cancelTokenSource) {
cancelTokenSource.cancel('Operation canceled by the user.');
cancelTokenSource = null;
}
cancelTokenSource = axios.CancelToken.source();
axios.get('http://api/uesr/12345',{cancelToken: cancelTokenSource.token}) //
.then(response => {
...
})
}
</script>
兼容
注意: 可以使用同一个 cancel token 或 signal 取消多个请求。
在过渡期间,您可以使用这两种取消 API,即使是针对同一个请求
const controller = new AbortController();
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token,
signal: controller.signal
}).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.');
// 或
controller.abort(); // 不支持 message 参数
拓展
AbortController的作用?
AbortController
是 Web API 的一部分,提供了一种可以控制一个或多个异步操作的请求是否应该被取消的方法。它允许开发者通过编程方式通知某些操作提前终止,这对于优化用户体验和资源管理非常重要。例如,用户可能在网页上发起一个网络请求,但随后又决定取消这个请求;这时就可以使用 AbortController
来实现。
主要特性
- 创建控制器:通过
new AbortController()
创建一个新的AbortController
实例。- 信号(Signal):每个
AbortController
都有关联的AbortSignal
对象,可以通过controller.signal
获取。这个信号对象可以传递给任何支持取消机制的操作,如fetch
请求。- 取消操作:调用
controller.abort()
方法来发出取消信号,这将导致所有监听该AbortSignal
的操作接收到取消指令,并相应地处理取消逻辑。应用场景
- 取消 Fetch 请求:最典型的使用场景之一。
- 取消 WebSocket 连接:虽然 WebSocket API 不直接支持
AbortController
,但可以在连接打开之前检查signal.aborted
状态,或者在收到消息时处理取消情况。- 取消定时任务:结合
setTimeout
和clearTimeout
使用AbortController
来管理定时器。- 其他异步操作:任何支持
AbortSignal
的 API 都可以利用AbortController
来实现操作的取消功能。
总之,AbortController
提供了一个简单而强大的工具,用于管理和取消异步操作,从而增强了应用程序对资源的控制能力和用户体验。