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

如何在不关闭底层WebSocket的前提下对WebSocketSubject使用firstValueFrom

方案1:加空订阅保活(零侵入改造成本最低)

WebSocketSubject默认会在所有活跃订阅都退订时关闭底层连接,你只需要提前给实例加一个永久空订阅占住引用计数,firstValueFrom的临时订阅退订后就不会触发连接关闭:

import { WebSocketSubject } from 'rxjs/webSocket';
import { firstValueFrom, filter } from 'rxjs';

let websocket = new WebSocketSubject<any>(url);
// 新增空订阅保活,连接不会自动关闭
const keepAliveSub = websocket.subscribe();

// 原有逻辑完全不需要修改
let firstMessage = await firstValueFrom(websocket.pipe(filter(m => true)));

// 后续需要主动关闭连接时,再取消保活订阅即可
// keepAliveSub.unsubscribe()

方案2:用share操作符封装多播层(无额外维护成本)

如果不想手动管理保活订阅,可以用RxJS7+的share操作符配置多播层,拦截退订请求不传递给底层WebSocketSubject,所有收发逻辑和原生WebSocketSubject用法完全一致,不需要区分两个实例:

import { WebSocketSubject } from 'rxjs/webSocket';
import { firstValueFrom, filter, share } from 'rxjs';

let websocket = new WebSocketSubject<any>(url).pipe(
  share({
    // 引用计数归零时不取消源订阅,不会关闭WebSocket
    resetOnRefCountZero: false
  })
);

// 正常调用firstValueFrom即可,不会触发连接关闭
let firstMessage = await firstValueFrom(websocket.pipe(filter(m => true)));
// 发送上行消息逻辑也不变,直接调用next即可
websocket.next({ type: 'ping' });

// 需要关闭连接时直接调用底层subject的complete方法即可
// websocket.source.complete()

原理解释

两个方案都是基于WebSocketSubject的默认行为设计:只有当所有直接订阅源Subject的订阅都退订时,才会触发底层连接关闭。方案1是用空订阅占住引用计数,方案2是用多播层把所有订阅都拦截在share内部,退订只会减少多播层的引用计数,不会传递给源WebSocketSubject,自然不会触发连接关闭。
两个方案都不需要重写firstValueFrom、不需要维护双实例、不需要用到冗余的multiplex能力,完全匹配需求。

内容的提问来源于stack exchange,提问作者Jean Hominal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 21:36:04