侧边栏壁纸
  • 累计撰写 47 篇文章
  • 累计创建 2 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

数据的流式获取

数据流式获取主要适用于实时性要求高的场景,如聊天、实时推送、大文件下载/上传、日志流等。

  1. WebSocket

    双向全双工通信,适合高实时性场景。

const ws = new WebSocket('wss://api.example.com/stream');

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('收到流式数据:', data);
};

ws.onopen = () => {
  ws.send(JSON.stringify({ type: 'subscribe' }));
};
  1. Server-Sent Events (SSE)

    单向服务器推送,基于 HTTP 协议,自动重连。

const eventSource = new EventSource('/api/stream');

eventSource.onmessage = (event) => {
  console.log('收到数据:', JSON.parse(event.data));
};

eventSource.onerror = (err) => {
  console.error('SSE 错误:', err);
};

服务器响应头需包含:

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
  1. Fetch API + ReadableStream

    处理分块响应,适用于大文件下载、流式 API。

fetch('/api/stream-data')
  .then(response => {
    const reader = response.body.getReader();
    const decoder = new TextDecoder();

    function readChunk() {
      return reader.read().then(({ done, value }) => {
        if (done) return;
        
        const chunk = decoder.decode(value);
        console.log('收到块:', chunk);
        
        // 继续读取下一块
        return readChunk();
      });
    }
    
    return readChunk();
  });
  1. WebRTC DataChannel

    点对点低延迟传输,适合视频流、游戏等场景。

  2. 轮询与长轮询

    短轮询:定时请求,简单但实时性差。
    长轮询:服务器持有请求直到有数据,比短轮询实时性好。

它们的区别
特性 短轮询 长轮询 Server-Sent Events (SSE) Fetch + ReadableStream WebSocket
核心模型 客户端定时“拉取” 客户端挂起式“拉取” 服务器单向“推送” 单向“响应流” 双向“对话”
通信方向 准双向 (由请求发起) 准双向 (由请求发起) 单向 (服务器 → 客户端) 单向 (服务器响应流 → 客户端) 全双工双向 (随时互发)
协议基础 HTTP/HTTPS (普通请求) HTTP/HTTPS (长连接) HTTP/HTTPS (长连接) HTTP/HTTPS (单次请求) 独立的 ws/wss 协议
连接方式 短连接 (请求完即关) 长连接 (服务器挂起) 持久连接 (服务器可主动发) 单次连接 (流结束即关) 持久连接 (升级后专用)
实时性 (延迟=轮询间隔) 较好 (数据就绪即返回) (数据就绪即推送) (数据块就绪即传输) 极好 (毫秒级双向)
服务器压力 很高 (大量无效请求) 中等 (挂起减少请求数) 低 (一个连接持续推送) 低 (单次流式响应) 极低 (无头开销,长连接)
数据格式 任意 (JSON 等) 任意 (JSON 等) 文本 (event-stream 格式) 任意 (文本/二进制) 任意 (文本/二进制)
背压控制 原生支持 (可暂停流) 无 (网络层控制)
典型场景 兼容性要求极高的旧系统 需较好实时性但无法用 SSE/WS 实时通知、行情、日志 (如 ChatGPT 流) 大文件下载、AI 文本流、视频 聊天、游戏、协同编辑、实时交易
实现复杂度 非常简单 较复杂 (需处理超时重连) 简单 中等 (需处理流读取) 中等 (需处理协议状态)
核心区别详解
  1. 主动性:谁发起数据流动?

    短/长轮询 (Pull - 拉) :客户端驱动。像不断打电话问“有消息吗?”。
    SSE/WebSocket (Push - 推) :服务器驱动。像订阅了频道,消息来了就直接送到。
    Fetch Stream (Stream - 流) :客户端发起,服务器流式响应。像打开水龙头,水持续流出来。

  2. 连接与开销的本质区别

    短轮询是“勤问但笨”:无论有无新消息,都频繁敲门问,浪费体力(网络开销)。
    长轮询是“等信再问”:站在门口等,一有信就收,收完继续等。比短轮询聪明,但仍需“站”这个动作(保持 HTTP 请求)。
    SSE 是“装了个信箱”:信箱(HTTP 连接)装好后,邮差(服务器)有信就直接投进去。
    Fetch Stream 是“接了一根水管”:打开阀门(发起请求),水(数据)就持续流过来,流完管子就拆。
    WebSocket 是“接了条热线电话”:电话接通后,双方可以随时说话,没有拨号开销。

  3. 单向与双向的鸿沟

    SSE 和 Fetch Stream 是单向高速公路:数据只能从服务器流向客户端。
    WebSocket 是双向立交桥:数据可以随时双向自由通行。
    轮询是双向乡间小道:每次只能单向走一辆车(请求或响应),需要来回掉头。

  4. “流”的特有优势:背压控制

这是 Fetch + ReadableStream独有优势。客户端可以主动控制数据流的接收速度,比如:

const reader = response.body.getReader();
// 客户端可以根据处理能力暂停读取
if (bufferIsFull) {
  await delay(100); // 暂停一下,防止内存溢出
}
await reader.read(); // 继续读取下一块

这在下载超大文件或处理慢速消费的流时至关重要,而其他方案不具备这种原生应用层控制。

如何选择?
  1. 需要客户端随时主动向服务器发消息吗?

    → 只能选 WebSocket

    → 进入第 2 题。

  2. 主要是处理一个大文件的下载,或一个很长的文本生成,需要控制接收速度吗?

    → 选 Fetch + ReadableStream

    → 进入第 3 题。

  3. 主要是服务器有事件就实时推给客户端,且客户端只需偶尔发送指令(用另一个普通 HTTP 请求)?

    → 选 SSE

    → 进入第 4 题。

  4. 对实时性要求一般,但服务器或浏览器太老,不支持 SSE/WS?

    对实时性有要求 → 用 长轮询

    对实时性几乎没要求(比如每分钟同步一次)→ 用 短轮询

0

评论区