前端如何终止请求
目录
- AbortController 构造函数
- controller.signal
- controller.abort()
- 举例说明-模拟异步操作
- 与Fetch API集成
- 与Axios集成
- 实际应用:Vue中使用
- 其他终止请求
- XMLHttpRequest
AbortController 构造函数
AbortController构造函数 是一个用于中止一个或多个 Web 请求Web API;但也可以用于其他异步操作。
它提供了一个signal
属性,可以传递给异步操作(如fetch),然后在需要时通过调用abort
方法来中止这些操作。
const controller = new AbortController()
const { signal } = controllercontroller.abort() // 终止请求
controller.signal
controller.signal 是 AbortController 实例的一个只读
属性,它返回一个 AbortSignal 信号对象用于通信和取消异步请求/操作
。
- 属性
signal.aborted : 请求是否被终止
signal.reason: 请求终止原因// 初始状态 { aborted: false, reason: undefined } // 调用 abort(): { aborted: true, reason: '提供的理由' }
- signal上存在abort事件:当异步被终止时触发
signal.addEventListener('abort', function(){}, false)
不可逆转: 一旦中止,信号永远保持中止状态
controller.abort()
controller.abort是AbortController 实例用于终止请求的方法 => 调用controller.abort会中止所有使用该controller的signal属性的异步操作
不会影响不使用此signal的操作。
一个AbortController可以用于多个异步操作,一次abort调用会中止所有相关操作
当调用 abort() 时,信号的状态变化会通知所有使用该信号的操作
当操作被终止时会抛出一个名为AbortError
的异常。
举例说明-模拟异步操作
<body><ul class="box"></ul><button class="btn">终止请求</button><script>const controller = new AbortController()const { signal } = controllerconst box = document.querySelector('.box')// 模拟5个异步操作都是使用的同一个singnal => 给5个li元素添加内容for(let i=0;i<5;i++){const li = document.createElement('li')box.appendChild(li)// 创建多个异步-使用定时器模拟异步任务const timer = setTimeout(function(){if(!signal.aborted) {li.innerText = '请求完成'}}, i*1000)signal.addEventListener('abort', function(e){// 异步已经被终止了=> 使用定时器模拟异步清除定时器相当于取消异步请求clearTimeout(timer)if(!li.innerHTML) {// 还存在如下没有请求完成的任务li.innerHTML = '请求被终止'}}, false)}// 终止请求const btn = document.querySelector('.btn')btn.onclick = function(){btn.disabled = truecontroller.abort()}</script>
</body>
与Fetch API集成
const controller = new AbortController();
const signal = controller.signal;fetch('/api/data', { signal }).then(response => {// 检查信号状态---tips其实这里不需要检查因为当终止请求时会抛出一个错误就走到catch里面了if (signal.aborted) {console.log('请求已被取消,忽略结果');return;}return response.json();}).catch(error => {if (error.name === 'AbortError') {console.log('请求被主动取消');} else {console.error('其他错误:', error);}});
上述代码在发送请求时将signal传入 => 若是想要终止请求直接调用controller.abort方法 => 请求被终止后会抛出一个异常,需要在catch里面捕获一下。
const controller = new AbortController();
const signal = controller.signal;// 多个操作使用同一个信号
const requests = [fetch('/api/data1', { signal }),fetch('/api/data2', { signal }),fetch('/api/data3', { signal })
];// 一次性取消所有请求
controller.abort();
与Axios集成
// 引入 Axios 和 AbortController
import axios from 'axios';// 创建 CancelToken Source (旧版API,已不推荐)
// const CancelToken = axios.CancelToken;
// const source = CancelToken.source();// 正确的新版方式:使用 AbortController
const controller = new AbortController();// 发起请求,传入 signal
axios.get('https://api.example.com/data', {signal: controller.signal
})
.then(response => {console.log(response.data);
})
.catch(err => {if (axios.isCancel(err)) {console.log('请求取消:', err.message);} else {console.error('其他错误:', err);}
});// 取消请求,并提供一个可选的消息
controller.abort('操作被用户取消');// 旧版取消方式(已弃用):
// source.cancel('操作被用户取消');
实际应用:Vue中使用
import { ref, onUnmounted } from 'vue';
import axios from 'axios';export default {setup() {const data = ref(null);const loading = ref(false);const error = ref(null);const controller = ref(null);const fetchData = async () => {// 取消之前的请求if (controller.value) {controller.value.abort();}loading.value = true;error.value = null;controller.value = new AbortController();try {const response = await axios.get('/api/data', {signal: controller.value.signal,timeout: 10000});data.value = response.data;} catch (err) {// 检查是否是取消错误if (axios.isCancel(err)) {console.log('请求被取消');} else if (err.name === 'CanceledError') {console.log('请求被取消 (AbortController)');} else {error.value = err.message;console.error('请求错误:', err);}} finally {loading.value = false;}};const cancelRequest = () => {if (controller.value) {controller.value.abort();controller.value = null;loading.value = false;}};onUnmounted(() => {cancelRequest();});return {data,loading,error,fetchData,cancelRequest};}
};
其他终止请求
XMLHttpRequest
XMLHttpRequest实例对象.abort方法终止请求