要实现类似 ChatGPT 的流式响应 UI,前端需要处理实时数据流并动态更新界面。以下是核心实现方案:
一、核心技术方案
数据获取方式:
- 使用 fetch API + ReadableStream(推荐)
- 或 EventSource(SSE,仅 GET 请求)
- 或 WebSocket(双向通信场景)
核心流程:
二、代码实现(使用 Fetch API)
<div id="chat-container"></div>
<script>
// 1. 创建消息容器
const chatContainer = document.getElementById('chat-container');
// 2. 发起流式请求
async function sendMessage(message) {
// 创建AI消息占位元素
const aiMessage = createMessageElement('assistant');
try {
const response = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message }),
});
// 3. 处理流式响应
const reader = response.body.getReader();
const decoder = new TextDecoder();
let partialLine = '';
while (true) {
const { value, done } = await reader.read();
if (done) break;
// 4. 解码并处理数据块
const chunk = decoder.decode(value, { stream: true });
const lines = (partialLine + chunk).split(/\r?\n/);
partialLine = lines.pop() || ''; // 保存不完整行
for (const line of lines) {
if (!line.startsWith('data:')) continue;
const jsonStr = line.replace('data:', '').trim();
if (jsonStr === '[DONE]') break;
try {
const data = JSON.parse(jsonStr);
const token = data.choices[0].delta.content || '';
// 5. 增量更新DOM
aiMessage.innerHTML += escapeHtml(token); // 防XSS
// 6. 自动滚动(性能优化版)
requestAnimationFrame(() => {
chatContainer.scrollTop = chatContainer.scrollHeight;
});
} catch (e) {
console.error('解析错误:', e);
}
}
}
} catch (err) {
aiMessage.innerHTML += '<span class="error">请求失败</span>';
}
}
// 辅助函数:创建消息元素
function createMessageElement(role) {
const msgEl = document.createElement('div');
msgEl.className = `message ${role}`;
chatContainer.appendChild(msgEl);
return msgEl;
}
// 辅助函数:简易防XSS
function escapeHtml(text) {
return text
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">");
}
</script>
三、关键优化点
性能优化:
- 使用 requestAnimationFrame 节流滚动操作
- 避免频繁 DOM 操作:批量更新(如每 100ms 更新一次)
- 虚拟滚动(长对话场景)
用户体验:
// 打字机效果实现
function typewriterEffect(element, text, speed = 20) {
let i = 0;
const timer = setInterval(() => {
if (i < text.length) {
element.textContent += text.charAt(i++);
// 滚动保持可见
element.scrollIntoView({ behavior: 'smooth', block: 'end' });
} else {
clearInterval(timer);
}
}, speed);
}
- 错误处理:
- 网络错误重试机制
- 超时控制(AbortController)
- 不完整 JSON 的恢复处理
四、不同技术方案对比
方案 | 优点 | 缺点 | 适用场景 |
Fetch+Stream | 灵活、支持POST、HTTP标准 | 需手动解析 | 主流API交互 |
EventSource | 自动重连、简单易用 | 仅支持GET、无认证头 | 只读数据流 |
WebSocket | 双向实时通信 | 需要额外服务器支持 | 高频双向交互场景 |