使用 Uint8Array 和 ReadableStream 模拟服务器发送事件 (SSE)

41 min read

使用 Uint8ArrayReadableStream 模拟服务器发送事件 (SSE)

1. 背景

在 Web 开发中,服务器发送事件(SSE)是一种允许服务器主动向客户端发送数据的机制。为了模拟 SSE,我们可以使用 ReadableStreamUint8Array 来处理和传输二进制数据。

2. Uint8Array

Uint8Array 是一种类型化数组,用于处理原始二进制数据。每个元素都是 8 位无符号整数(0 到 255),占用一个字节的内存。

  • 创建 Uint8Array:

    const uint8 = new Uint8Array([0, 255, 128, 64]);
    console.log(uint8); // 输出: Uint8Array(4) [0, 255, 128, 64]
    
  • 常用方法:

    const uint8 = new Uint8Array(4);
    uint8.set([10, 20, 30, 40]);
    console.log(uint8); // 输出: Uint8Array(4) [10, 20, 30, 40]
    

3. TextEncoder

TextEncoder 是用于将字符串编码为 Uint8Array 的对象,使用 UTF-8 编码方案。

  • 使用示例:
    const encoder = new TextEncoder();
    const uint8Array = encoder.encode("Hello, world!");
    console.log(uint8Array); // 输出: Uint8Array(13) [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]
    

4. ReadableStreamDefaultController

ReadableStreamDefaultController 用于控制 ReadableStream 的状态,包括推送数据块、关闭流和处理错误。

  • 常用方法:
    • enqueue(chunk): 将数据块推送到流中。
    • close(): 关闭流。
    • error(e): 将流置于错误状态。

5. 使用 ReadableStream 模拟 SSE

通过结合 Uint8ArrayTextEncoderReadableStreamDefaultController,我们可以创建一个模拟 SSE 的类。

export class MockSSEResponse {
  private controller!: ReadableStreamDefaultController<Uint8Array>;
  private encoder = new TextEncoder();
  private stream: ReadableStream<Uint8Array>;

  constructor(
    private dataArray: string[],
    private delay: number = 300,
  ) {
    this.stream = new ReadableStream({
      start: (controller) => {
        this.controller = controller;
        this.pushData();
      },
    });
  }

  private pushData() {
    if (this.dataArray.length === 0) {
      this.controller.close(); // 数据发送完毕,关闭流
      return;
    }

    const chunk = this.dataArray.shift();
    this.controller.enqueue(this.encoder.encode(chunk!)); // 编码并推送数据块

    setTimeout(() => this.pushData(), this.delay); // 延迟后递归调用
  }

  getResponse() {
    return new Response(this.stream);
  }
}
  • 构造函数: 初始化 dataArraydelay,并创建一个新的 ReadableStream 实例。
  • pushData 方法: 从 dataArray 中获取数据块,使用 TextEncoder 编码为 Uint8Array,然后使用 enqueue 方法推送到流中。重复此操作直到所有数据发送完毕,并关闭流。
  • getResponse 方法: 返回包含流的 Response 对象。

结论

使用 Uint8ArrayReadableStream 可以有效地模拟服务器发送事件(SSE),通过 TextEncoder 将字符串数据编码为二进制数据,并通过 ReadableStreamDefaultController 控制数据流的推送和关闭。这个方法在开发和测试需要模拟 SSE 场景时非常有用。