肥仔教程网

SEO 优化与 Web 开发技术学习分享平台

前端如何处理流式响应?

要实现类似 ChatGPT 的流式响应 UI,前端需要处理实时数据流并动态更新界面。以下是核心实现方案:

一、核心技术方案

数据获取方式:

  1. 使用 fetch API + ReadableStream(推荐)
  2. 或 EventSource(SSE,仅 GET 请求)
  3. 或 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>

三、关键优化点

性能优化:

  1. 使用 requestAnimationFrame 节流滚动操作
  2. 避免频繁 DOM 操作:批量更新(如每 100ms 更新一次)
  3. 虚拟滚动(长对话场景)

用户体验:

// 打字机效果实现
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);
}
  1. 错误处理
  2. 网络错误重试机制
  3. 超时控制(AbortController)
  4. 不完整 JSON 的恢复处理

四、不同技术方案对比

方案

优点

缺点

适用场景

Fetch+Stream

灵活、支持POST、HTTP标准

需手动解析

主流API交互

EventSource

自动重连、简单易用

仅支持GET、无认证头

只读数据流

WebSocket

双向实时通信

需要额外服务器支持

高频双向交互场景

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言