用 abortcontroller 可实现带取消按钮的下载任务:1. 创建控制器并传 signal 给 fetch;2. 按钮点击时调 controller.abort() 并禁用按钮;3. 大文件下载可用 reader.read() 配合 signal.aborted 实时检查;4. 注意 signal 不复用、不终止底层连接。

用 AbortController 实现带取消按钮的下载任务,核心是把 fetch 请求和按钮点击事件联动起来:点击取消时调用 controller.abort(),中断正在进行的请求。
1. 创建 AbortController 并传入 fetch
在发起下载前新建控制器,把它的 signal 传给 fetch 选项。这样 fetch 就能监听中止信号:
const controller = new AbortController();
const signal = controller.signal;
fetch(url, { signal })
.then(response => {
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.blob();
})
.then(blob => {
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'file.zip';
a.click();
URL.revokeObjectURL(a.href);
})
.catch(err => {
if (err.name === 'AbortError') {
console.log('下载已取消');
} else {
console.error('下载失败:', err);
}
});
2. 绑定取消按钮并触发 abort()
给取消按钮添加点击事件,调用 controller.abort()。注意:abort 后 signal 会立即变为 aborted: true,且不可重用:
- 确保按钮在请求发起后才可点击(比如禁用初始状态,fetch 开始后启用)
- 点击后应禁用按钮,避免重复 abort(虽然多次调用无副作用,但逻辑更清晰)
- 可选:清空 controller 引用,防止内存泄漏(尤其在单页应用中频繁创建)
3. 处理流式下载(大文件/进度反馈)
如果需要显示下载进度或处理大文件,建议用 response.body.getReader() 读取流,并在每次 read() 前检查 signal.aborted:
const reader = response.body.getReader();
let loaded = 0;
const contentLength = +response.headers.get('content-length');
while (true) {
const { done, value } = await reader.read();
if (done) break;
if (signal.aborted) {
reader.cancel('Download canceled');
throw new DOMException('Download canceled', 'AbortError');
}
loaded += value.length;
updateProgress(loaded, contentLength);
}
4. 注意事项与常见坑
-
AbortController 不终止网络连接本身,只是让 fetch 抛出
AbortError并停止后续处理;底层 TCP 连接可能稍后才关闭 -
不能跨请求复用 signal:每个 fetch 需要独立的
AbortController -
XMLHttpRequest 也支持 signal,但需手动监听
onabort,不如 fetch 原生集成方便 - 服务端若已开始传输,客户端 abort 不影响服务端行为(如日志、计费等),需后端配合支持取消语义
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











