
通过服务端流式响应(server-send events 或 streaming json),前端可在部分数据就绪时立即接收并渲染,无需等待全部 100+ 个 fetch 完成,显著提升首屏响应速度与用户体验。
通过服务端流式响应(server-send events 或 streaming json),前端可在部分数据就绪时立即接收并渲染,无需等待全部 100+ 个 fetch 完成,显著提升首屏响应速度与用户体验。
传统方案中,后端串行或并行发起大量 fetch 请求,再统一 Promise.all 等待全部完成才返回聚合结果,导致前端长时间白屏或加载中。这种“全有或全无”的模式严重违背现代 Web 的渐进式渲染理念。
✅ 推荐方案:服务端流式输出 + 前端流式消费
后端不再缓存全部结果,而是每完成一个 (origin, destiny) 请求,就立即向响应流中写入一条结构化数据(如 NDJSON 或 SSE 格式);前端通过 ReadableStream 或 EventSource 持续读取,边收边处理、边渲染。
后端示例(Node.js + Express,使用 NDJSON 流):
app.post('/api/batch-search', async (req, res) => {
res.setHeader('Content-Type', 'application/x-ndjson');
res.setHeader('Cache-Control', 'no-cache');
res.flushHeaders(); // 确保头部立即发送
const { originList, destinationList } = req.body;
const promises = [];
for (const origin of originList) {
for (const destiny of destinationList) {
const url = `https://api.example.com/route?from=${origin}&to=${destiny}`;
promises.push(
fetch(url)
.then(r => r.json())
.then(data => {
// 立即写入单条 JSON 行(NDJSON)
res.write(JSON.stringify({ origin, destiny, text: data.text }) + '\n');
})
.catch(err => {
res.write(JSON.stringify({ origin, destiny, error: err.message }) + '\n');
})
);
}
}
// 所有请求启动后,等待全部结束(但不阻塞流输出)
await Promise.allSettled(promises);
res.end(); // 流结束标记
});
前端示例(React + ReadableStream):
PigX UI Pro 前端开发指南 - Vue 3 + TypeScript + Element Plus。当用户提到 PigX UI、PigX 前端、lgb-mgui 项目、Vue 3 企业级后台开发、Element Plus 后台开发时使用此技能。
const BatchSearch = () => {
const [results, setResults] = useState<any>([]);
useEffect(() => {
const controller = new AbortController();
fetch('/api/batch-search', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ originList, destinationList }),
signal: controller.signal,
})
.then(async (res) => {
if (!res.body) throw new Error('ReadableStream not supported');
const reader = res.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const line = decoder.decode(value).trim();
if (!line) continue;
try {
const item = JSON.parse(line);
setResults(prev => [...prev, item]);
} catch (e) {
console.warn('Invalid NDJSON line:', line);
}
}
})
.catch(err => console.error('Stream error:', err));
return () => controller.abort();
}, []);
return (
<div>
{results.map((r, i) => (
<div key="{i}">{r.origin} → {r.destiny}: {r.text || r.error}</div>
))}
</div>
);
};</any>
⚠️ 注意事项:
-
兼容性:
ReadableStream在现代浏览器中支持良好(Chrome/Firefox/Safari ≥ 16),若需支持旧版,可用EventSource替代(要求后端改用 SSE 格式); -
错误容错:使用
Promise.allSettled而非Promise.all,确保单个请求失败不影响其余结果流式输出; -
内存控制:前端应避免无限累积
results,可结合分页、虚拟滚动或仅保留最新 N 条; -
CORS 与 Headers:确保后端设置
Access-Control-Allow-Origin及Content-Type,且禁用Content-Encoding: gzip(流式传输通常不压缩); -
超时与取消:务必实现
AbortController,防止用户离开页面后请求仍在后台运行。
总结:将“批量聚合返回”重构为“事件驱动流式响应”,是处理高并发、低延迟数据场景的关键范式升级。它不仅降低感知延迟,还使系统更具韧性与可观测性——每个结果都自带时间戳和上下文,便于调试与监控。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!








