JavaScript中处理大模型流式响应的核心是消费Response.body可读流:设Accept为text/event-stream或text/plain,用TextDecoderStream解码,lines()分割每行,逐行解析JSON或SSE,配合AbortController和try/catch保障健壮性。

JavaScript 中用 fetch 处理聊天大模型的流式响应(如 OpenAI、Ollama、vLLM 等返回的 text/event-stream),核心是读取 Response.body 的可读流(ReadableStream),配合 TextDecoderStream 解码字节流为字符串,并逐块解析 SSE(Server-Sent Events)或纯文本流。关键不是“等全部返回”,而是边接收、边解码、边处理。
获取流式响应并接入可读流
调用 fetch 时需显式设置 headers.Accept = 'text/event-stream'(若后端支持 SSE),或直接接受 text/plain 流;同时确保后端未禁用流传输(如 Express 需禁用 res.flush() 干预,FastAPI 默认支持)。拿到响应后,不调用 response.json() 或 response.text(),而是用 response.body 获取底层流:
-
response.body是一个ReadableStream<uint8array></uint8array> - 必须用
getReader()或pipeThrough()消费,否则流会挂起 - 记得检查
response.ok和response.status,流式请求失败仍可能返回非 2xx 状态码
用 TextDecoderStream 实时解码字节流
原始流是 Uint8Array,需转为字符串才能按行或按事件解析。推荐使用内置的 TextDecoderStream(无需手动 new TextDecoder().decode())——它能自动处理多字节字符跨 chunk 边界的问题:
const decoder = new TextDecoderStream('utf-8');const decodedStream = response.body.pipeThrough(decoder);- 后续可接
lines()转换器(见下一点)或直接用getReader() - 避免用
TextDecoder手动 decode:对分片到达的 UTF-8 字节(如 emoji、中文)易出错
按行或按事件解析流数据
大多数大模型 API 返回的是行分隔的流(每行一个 JSON 对象,或 SSE 格式)。可借助 TransformStream 构建 lines() 工具流:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
async function* lines(stream) {
const reader = stream.getReader();
let buffer = '';
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += value;
let i;
while ((i = buffer.indexOf('\n')) >= 0) {
const line = buffer.slice(0, i).trim();
if (line) yield line;
buffer = buffer.slice(i + 1);
}
}
if (buffer) yield buffer.trim();
} finally {
reader.releaseLock();
}
}然后这样使用:
const decoded = response.body.pipeThrough(new TextDecoderStream());for await (const line of lines(decoded)) { /* 处理每一行 */ }- 若后端返回 SSE(
data: {...}\n\n),可用正则提取data:后内容,再JSON.parse() - 若返回纯 JSONL(每行一个完整 JSON),直接
JSON.parse(line)即可
安全处理与错误防护
流式响应容易因网络中断、服务超时、格式错误而中断,需主动兜底:
- 用
AbortController控制请求生命周期,例如用户点击“停止生成”时abort() - 在
for await循环中捕获TypeError: Failed to fetch或DOMException: The operation was aborted - 对每条
line做try/catch,跳过非法 JSON 行(如空行、注释、心跳 ping) - 设置超时:流长时间无新数据(如 30s)可视为卡死,主动 close
- 前端需防重复提交:发送请求前禁用按钮,成功/失败后恢复
不复杂但容易忽略:流式响应依赖服务端正确设置 Content-Type、禁用缓冲(如 Nginx 的 proxy_buffering off)、保持连接不被中间件截断。前端只需专注消费流、解码、解析、渲染,就能实现接近原生的对话体验。

















