fetch 流式传输终止需主动关闭 readablestream reader 并用 abortcontroller 中断请求;fetch 本身不支持取消,abort() 使 promise 拒绝为 aborterror,已获取 response 后需显式 reader.cancel() 释放资源,推荐先 cancel 再清理。

Fetch 处理流式传输(如 Server-Sent Events、大文件下载或实时日志)时,终止操作的核心在于主动关闭 ReadableStream 的 reader,并中断底层请求。浏览器不会自动释放流资源,不手动清理会导致内存泄漏或连接持续占用。
取消 fetch 请求本身
原生 fetch 不支持直接取消,但可通过 AbortController 中断请求。一旦调用 abort(),fetch Promise 会以 AbortError 拒绝,且响应体流(response.body)将不可读。
- 创建
AbortController实例,传入signal到 fetch 选项 - 调用
controller.abort()后,已开始的流读取会立即抛出TypeError: Failed to read the 'body' property或AbortError - 注意:若已获取到
Response对象(即 fetch 成功 resolve),则abort()不影响已建立的流,需额外关闭 reader
关闭正在读取的 ReadableStream
即使 fetch 成功,只要还在用 reader.read() 持续消费流,就必须显式调用 reader.cancel() 或 reader.closed 监听 + reader.releaseLock() 来释放锁和资源。
-
reader.cancel(reason)会终止流并拒绝当前及后续read()调用,适合主动停止场景 -
reader.releaseLock()仅在流未关闭时解除 reader 对流的独占访问,不终止流;必须确保不再调用read() - 推荐模式:在终止逻辑中先
reader.cancel(),再处理 cleanup(如清空缓冲、重置状态)
监听流结束与异常边界
流可能因网络中断、服务端关闭或 abort 而提前终止,需统一捕获 read() 的 reject 和 done === true 的完成信号。
-
reader.read()返回 Promise,fulfill 时检查{ value, done }——done: true表示流自然结束 - Promise reject 可能是网络错误、abort 或流被 cancel,应统一处理并避免重复 cancel
- 不要依赖
response.body.getReader()抛异常来判断终止;它只在流已 lock 或已 cancel 后才报错
完整终止示例(SSE 场景)
以下是一个可安全终止的流读取封装:
let controller = null;
let reader = null;
async function startStream(url) {
controller = new AbortController();
try {
const res = await fetch(url, { signal: controller.signal });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
reader = res.body.getReader();
while (true) {
const { value, done } = await reader.read();
if (done) break;
// 处理 chunk(如 TextDecoder.decode(value))
}
} catch (err) {
if (err.name === 'AbortError') {
console.log('请求已被取消');
} else {
console.error('流读取异常', err);
}
} finally {
if (reader) {
await reader.cancel(); // 确保流被取消
reader = null;
}
}
}
function stopStream() {
if (controller) controller.abort();
}
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











