ReadableStream.getReader() 返回 ReadableStreamDefaultReader,需手动调用 read() 获取数据;read() 返回 Promise,done 为 true 时流结束,value 为 undefined;Uint8Array 需用 TextDecoder 解码;cancel() 终止流,releaseLock() 仅释放读取权。

ReadableStream.getReader() 返回的 reader 怎么用
直接调用 getReader() 得到的是一个 ReadableStreamDefaultReader,它不自动读取数据,也不触发流消费——你得手动调用 reader.read() 才会拉取下一块。常见错误是以为调用 getReader() 后流就“开始流了”,其实只是拿到了控制权。
典型使用场景包括:处理大文件上传响应、解析长 JSON 流、实时日志流、或避免一次性加载整个 Response.body 到内存。
-
reader.read()返回 Promise - 当
done === true时,流已彻底结束,value为undefined - 每次
read()只取一块(chunk),大小由底层决定,不是固定字节数 - 不能对同一个 reader 多次并发调用
read();必须等前一个 Promise settle 后再调下一个
为什么用 while (true) + await read() 容易卡死
写成 while (true) { const { value, done } = await reader.read(); if (done) break; process(value); } 看似自然,但实际在某些环境(比如 Chrome DevTools 控制台、某些 Service Worker 上下文)中,如果流没有及时 push 数据,这个循环可能因 Promise 永不 resolve 而挂起整个 async 函数,且无超时提示。
更稳妥的做法是显式处理 pending 状态,并预留中断能力:
立即学习“前端免费学习笔记(深入)”;
- 用
for await...of更安全(它内部做了 done 判断和异常传播) - 若必须手动
read(),建议加if (!value && done) break;双重判断 - 避免在非流式上下文中(如普通 fetch 后直接 .body.getReader())误以为有持续 chunk —— 大多数 HTTP 响应 body 是单 chunk 或两 chunk(header + body),除非服务端启用了 Transfer-Encoding: chunked 或 streaming JSON
Uint8Array 怎么转成字符串或 JSON
reader.read() 返回的 value 是 Uint8Array,不是字符串。直接 value.toString() 会得到逗号分隔的数字列表,不是原始文本。
- 转字符串:用
new TextDecoder().decode(value)(推荐,支持 UTF-8 自动处理) - 转 JSON(假设流是合法 JSON 分块):先累积所有
Uint8Array到Uint8Array合并数组,再整体 decode;不要每块都JSON.parse(),因为 JSON 不可分割(比如{"a":可能在第一块,1}在第二块) - 若需边收边解析(如 NDJSON / JSONL),每块需按换行切分,再逐行
JSON.parse(),注意跨块换行断裂问题
reader.cancel() 和 reader.releaseLock() 的区别在哪
这两个方法常被混淆:cancel() 是通知流“我不需要后续数据了”,会触发流的取消逻辑(如 abort underlying source),适合出错或提前终止;releaseLock() 只是释放 reader 对流的独占权,让其他 reader 可以获取——但流本身还在运行,且你不能再用这个 reader。
- 一旦调用
releaseLock(),再调read()会抛TypeError: Reader was released - 流结束(
done === true)后,reader 自动释放锁,无需手动releaseLock() - 忘记
cancel()可能导致资源泄漏(比如 Fetch 中的连接未关闭),尤其在 abort 逻辑里 - 在
finally块中根据状态选择调用:正常结束不用 cancel,异常或中断才reader.cancel()
真正难的不是调用 getReader(),而是理解流的生命周期与 reader 的所有权模型——它不像 Node.js 的 Readable 那样有 pause/resume,也没有内置缓冲区管理,所有节流、错误恢复、编码转换都得自己兜底。



















