当前位置: 首页 > news >正文

前端开发处理‘流式数据’与‘非流式数据’,在接收完整与非完整性数据时应该如何渲染和使用

在前端开发中,处理 非流式数据流式数据 的方式不同。根据是否完整接收数据、是否实时渲染的需求,可以分为以下四种典型场景:


一、四类常见场景总结

类型数据完整性是否实时渲染适用技术/方法
A完整数据(一次性返回)否(等全部加载完)fetch, axios, JSON.parse()
B完整数据(一次性返回)是(模拟逐字显示)setTimeout / requestAnimationFrame 模拟打字效果
C不完整数据(分段传输)否(等全部加载完)buffer 缓存 + 最终解析
D不完整数据(分段传输)是(边接收边渲染)ReadableStream, SSE, WebSocket, JSON 增量解析

场景对比表

场景是否流式是否实时渲染是否需要增量解析代表应用
A非流式不需要获取静态数据
B非流式不需要AI 回答展示
C流式需要日志聚合、大文件解析
D流式需要AI 聊天机器人、代码生成器

具体情况和项目还需要具体分析,并非生搬这四种场景。以下为场景对比的详解与实现:

场景详解与实现方案


场景 A:完整数据 + 非实时渲染(最常见)

适用于传统 API 请求,如获取用户列表、文章内容等。

示例代码:
const response = await fetch('/api/data');
const data = await response.json();
render(data);
渲染逻辑:
function render(data) {document.getElementById('content').innerText = data.content;
}

场景 B:完整数据 + 实时渲染(模拟打字效果)

适用于需要“逐字显示”的视觉效果,比如 AI 对话界面。

示例代码:
const response = await fetch('/api/data');
const data = await response.json();simulateTyping(data.content, document.getElementById('output'), 50);
打字函数实现:
function simulateTyping(text, element, interval = 50) {let index = 0;const timer = setInterval(() => {if (index < text.length) {element.textContent += text[index++];} else {clearInterval(timer);}}, interval);
}

场景 C:不完整数据 + 非实时渲染(等待拼接完成)

适用于大文件下载、日志聚合等场景,需等到所有数据接收完毕后再统一处理。

示例代码:
let buffer = '';while (true) {const { done, value } = await reader.read();if (done) break;buffer += decoder.decode(value, { stream: true });
}// 等待完成后统一解析
const finalData = JSON.parse(buffer);
render(finalData);

场景 D:不完整数据 + 实时渲染(流式解析 + 边接收边展示)

适用于 AI 流式回复、聊天机器人、代码生成器 等场景,需边接收边解析边渲染。

核心流程:
  1. 接收 chunk 数据
  2. 拼接到 buffer
  3. 尝试增量解析
  4. 提取有效字段并更新 UI
示例代码(结合 jsonparse):
import sax from 'jsonparse';let buffer = '';
const parser = new sax.Parser();parser.onValue = function (value) {if (this.stack.length === 1 && this.key === 'content') {updateUI(value); // 实时渲染 content 字段}
};async function processStream() {const response = await fetch('/api/stream-endpoint', {method: 'POST',body: JSON.stringify({ prompt: '讲个故事' })});const reader = response.body.getReader();const decoder = new TextDecoder();while (true) {const { done, value } = await reader.read();if (done) break;buffer += decoder.decode(value, { stream: true });try {parser.write(buffer);buffer = ''; // 成功解析后清空 buffer} catch (e) {// 忽略不完整 JSON 错误,继续等待更多数据}}parser.close();
}function updateUI(text) {const container = document.getElementById('output');container.textContent += text;
}

技术选型建议

使用场景推荐技术
非流式完整数据fetch, axios, JSON.parse()
流式数据(HTTP SSE)EventSource, fetch + ReadableStream
WebSocket 数据流WebSocket, Socket.IO
JSON 增量解析jsonparse, clarinet
实时 UI 更新requestAnimationFrame, DOM diff, 节流控制

Vue / React 场景优化建议

Vue 示例(使用 ref 控制 DOM)

<template><div id="output">{{ outputText }}</div>
</template><script setup>
import { ref } from 'vue';
const outputText = ref('');function updateUI(text) {outputText.value += text;
}
</script>

React 示例(使用 useStateuseRef

function ChatBox() {const [text, setText] = useState('');const containerRef = useRef(null);function updateUI(chunk) {setText(prev => prev + chunk);setTimeout(() => {containerRef.current.scrollTop = containerRef.current.scrollHeight;}, 0);}return (<div ref={containerRef} style={{ height: '300px', overflowY: 'auto' }}>{text}</div>);
}

相关文章:

  • 从零开始构建文本统计模型:字符级与多字符片段频率分析实践
  • java30
  • HCIP(BGP综合实验)
  • linux批量创建文件
  • RHEL7安装教程
  • 【QT】自定义QWidget标题栏,可拖拽(拖拽时窗体变为normal大小),可最小/大化、关闭(图文详情)
  • Spring AI之RAG入门
  • SpringBoot3.2新特性:JdbcClient
  • 模块化交互数字人系统:OpenAvatarChat,单台PC即可运行完整功能
  • 【Redis】大key对持久化的影响
  • 定时器时钟来源可以从输入捕获引脚输入
  • Unity ARPG战斗系统 _ RootMotion相关知识点
  • GPTBots在AI大语言模型应用中敏感数据匿名化探索和实践
  • 基于InternLM的情感调节大师FunGPT
  • agent mode 代理模式,整体要求,系统要求, 系统指令
  • 2025年微信小程序开发:AR/VR与电商的最新案例
  • [Python] struct.unpack() 用法详解
  • 深入理解前端DOM:现代Web开发的基石
  • Tauri(2.5.1)+Leptos(0.7.8)开发桌面应用--简单的工作进度管理
  • 法律大语言模型(Legal LLM)技术架构
  • 广州有哪些网站建设/网络推广都有哪些方式
  • 做网站怎么样才能排在首页/网络营销属于什么专业类型
  • 媒体查询做响应式网站/沈阳seo合作
  • 动画型网站/乱码链接怎么用
  • 成都网站建设全平台/百度公司注册地址在哪里
  • 微信官网网站/友情链接免费发布平台