中止一个或多个 Web 请求
ajax 有主动结束请求的方法 Ajax.abort
Axios CancelToken
fetch ws 没有主动结束请求的方法
使用js的一个方法AbortController
AbortController 是一个 JavaScript API,用于中止一个或多个 Web 请求。
提供了一种标准化的方式来取消异步操作。
AbortController 由两部分组成:
AbortController:控制器对象,用于发送中止信号
AbortSignal:信号对象,用于监听中止事件
在fetch中的使用
// 1. 创建 AbortController 实例
const controller = new AbortController();
const signal = controller.signal;
// 2. 将 signal 传递给可中止的操作
fetch('/api/data', { signal })
.then(response => response.json())
.then(data => console.log(data))
.catch(err => {
if (err.name === 'AbortError') {
console.log('请求被中止');
} else {
console.error('请求错误:', err);
}
});
// 3. 中止请求
controller.abort(); // 这会触发 AbortError
主要应用场景
取消 Fetch 请求
取消 Axios 请求
中止任何支持 signal 的异步操作
清理事件监听器
取消长时间运行的任务
与 Fetch API 结合使用
const controller = new AbortController();
const signal = controller.signal;
// 设置超时自动取消
const timeoutId = setTimeout(() => controller.abort(), 5000);
fetch('https://api.example.com/data', { signal })
.then(response => {
clearTimeout(timeoutId);
return response.json();
})
.then(data => console.log(data))
.catch(err => {
if (err.name === 'AbortError') {
console.log('请求超时被取消');
} else {
console.error('请求错误:', err);
}
});
与 Axios 结合使用
const controller = new AbortController();
axios.get('/api/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();
复用同一个信号
const controller = new AbortController();
const signal = controller.signal;
// 多个请求使用同一个信号
fetch('/api/data1', { signal });
fetch('/api/data2', { signal });
fetch('/api/data3', { signal });
// 一次性取消所有请求
controller.abort();
监听中止事件
const controller = new AbortController();
const signal = controller.signal;
signal.addEventListener('abort', () => {
console.log('中止信号已触发');
// 执行清理操作
});
controller.abort(); // 会触发上面的监听器
自定义可中止操作
function doTask(signal) {
return new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => resolve('任务完成'), 5000);
// 监听中止信号
signal.addEventListener('abort', () => {
clearTimeout(timeoutId);
reject(new DOMException('任务被中止', 'AbortError'));
});
if (signal.aborted) {
clearTimeout(timeoutId);
reject(new DOMException('任务被中止', 'AbortError'));
}
});
}
const controller = new AbortController();
doTask(controller.signal)
.then(console.log)
.catch(err => {
if (err.name === 'AbortError') {
console.log('任务被手动中止');
}
});
// 2秒后中止任务
setTimeout(() => controller.abort(), 2000);
浏览器兼容性
现代浏览器(Chrome 66+, Firefox 57+, Safari 12.1+, Edge 16+)都支持
Node.js 从 v15.0.0 开始支持
对于旧环境可以使用 polyfill
在 AbortController 之前,常用的取消请求方式:
XMLHttpRequest 的 abort()
Axios 的 CancelToken
最佳实践
及时清理:不再需要的控制器应该被清理
错误处理:总是检查错误类型是否为 AbortError
避免内存泄漏:组件卸载时取消所有未完成的请求
合理使用:不要过度使用,只在必要时取消请求
http1 最多同时发送6个请求,也就是说 如果开了6ws, 那么页面上的任何接口的请求都发不出去
主动中断 XHR(fetch/axios)请求和SSE(Server-Sent Events)请求(笔记)
- fetch XHR 请求的主动中断
使用 AbortController,fetch 原生支持 AbortController 来中断请求。
// 创建一个 AbortController 实例
const controller = new AbortController();
const signal = controller.signal;
// 发起 fetch 请求时传入 signal
fetch('https://jsonplaceholder.typicode.com/todos/1', { signal })
.then(response => response.json())
.then(data => console.log(data))
.catch(err => {
if (err.name === 'AbortError') {
console.log('请求被中断');
} else {
console.error('请求出错', err);
}
});
// 需要中断请求时调用
controller.abort();
- axios XHR 请求的主动中断
2.1 使用 CancelToken(axios v0.22及以下)
import axios from 'axios';
const CancelToken = axios.CancelToken;
let cancel;
// 发起请求
axios.get('https://jsonplaceholder.typicode.com/todos/1', {
cancelToken: new CancelToken(function executor(c) {
cancel = c;
})
}).then(res => {
console.log(res.data);
}).catch(thrown => {
if (axios.isCancel(thrown)) {
console.log('请求被取消');
} else {
console.error('请求出错', thrown);
}
});
// 需要中断请求时调用
cancel('手动取消请求');
2.2 axios v1.0+ 推荐用 AbortController
const controller = new AbortController();
axios.get('https://jsonplaceholder.typicode.com/todos/1', {
signal: controller.signal
}).then(res => {
console.log(res.data);
}).catch(err => {
if (err.code === 'ERR_CANCELED') {
console.log('请求被取消');
} else {
console.error('请求出错', err);
}
});
// 需要中断请求时调用
controller.abort();
- SSE(Server-Sent Events)请求的主动中断
SSE 通常用 EventSource 或自定义 fetch+流的方式实现。
3.1 原生 EventSource
const es = new EventSource('/sse-url');
es.onmessage = (event) => {
console.log('收到消息:', event.data);
};
// 需要中断时
es.close();
3.2 fetch+流(如你的 MyStream 实现)
你需要保存 AbortController 实例,并在需要时调用 abort()。
class MyStream {
constructor() {
this.controller = null;
this.reader = null;
}
async getStream(url, onData, onEnd) {
this.controller = new AbortController();
const response = await fetch(url, { signal: this.controller.signal });
const reader = response.body.getReader();
this.reader = reader;
// 读取流数据
while (true) {
const { value, done } = await reader.read();
if (done) break;
onData(value);
}
onEnd();
}
abortStream() {
if (this.reader) this.reader.cancel();
if (this.controller) this.controller.abort();
}
}
// 使用
const stream = new MyStream();
stream.getStream('/sse-url', data => console.log(data), () => console.log('end'));
// 需要中断时
stream.abortStream();
- 结合 Vue 组件的实际用法
data() {
return {
controller: null,
}
},
methods: {
fetchData() {
this.controller = new AbortController();
fetch('/api/data', { signal: this.controller.signal })
.then(res => res.json())
.then(data => { /* ... */ })
.catch(err => {
if (err.name === 'AbortError') {
console.log('请求被中断');
}
});
},
abortFetch() {
if (this.controller) this.controller.abort();
}
}
总结
fetch/axios v1+ 推荐用 AbortController,调用 controller.abort() 主动中断。
axios v0.22- 用 CancelToken。
SSE 用 EventSource.close() 或自定义流时用 AbortController 和 reader.cancel()。
高频请求场景,一定要保存 controller/reader 实例,及时中断不再需要的请求,避免资源泄漏和页面卡死。
2020

被折叠的 条评论
为什么被折叠?



