You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS SSE:interval与fromEvent的客户端视角差异探究

为什么NestJS中两种SSE实现的多客户端行为差异?

核心原因在于Observable的创建逻辑、订阅上下文以及事件源的共享性完全不同,具体拆解如下:

1. interval实现:每个客户端拥有独立的私有数据流

当客户端连接/sse端点时,Nest会为每个连接单独调用sse()方法,返回一个全新的interval Observable:

  • interval属于冷Observable:每个订阅(即每个客户端连接)都会启动一个独立的定时器,维护自己的执行序列。也就是说,客户端A和客户端B的定时器是完全分开的,各自按5秒间隔触发。
  • 代码里的this.c++每次在map中执行时,会基于控制器实例的共享变量递增,但因为两个客户端的定时器触发时机不同,最终收到的hello: world - X内容也会不一样(比如A先收到world-1,B连接后可能收到world-2,后续各自的计数也是独立推进的)。
  • 本质是:每个客户端的Observable实例是独立的,数据流互不干扰。

2. fromEvent + EventEmitter实现:所有客户端共享全局事件流

/approvals端点的实现依赖Nest的单例EventEmitter:

  • Nest默认将EventEmitter注册为单例,所以整个应用中所有控制器注入的是同一个事件发射器实例。
  • fromEvent创建的Observable,本质是监听这个全局单例的NEW_APPROVAL_EVENT_NAME事件。不管多少客户端连接,每个客户端的订阅都会在同一个EventEmitter上注册监听器。
  • 当NEW_APPROVAL_EVENT_NAME事件被触发时,EventEmitter会把同一份ApprovalDTO数据推送给所有注册的监听器,因此所有客户端都会收到完全相同的消息。

补充:如何让interval实现也共享数据流?

如果想让interval的SSE端点也让所有客户端收到相同消息,可以用share()操作符将冷Observable转为热Observable,让多个订阅共享同一个数据流:

@Sse('sse-shared')
sseShared(): Observable<MessageEvent> {
  return interval(5000)
    .pipe(
      map((_) => ({ data: { hello: `world - ${this.c++}` }} as MessageEvent)),
      share() // 让所有订阅共享同一个定时器数据流
    );
}

这样所有客户端会同步收到相同的计数消息。

内容的提问来源于stack exchange,提问作者Johnny Goodman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 17:17:31