Angular 如何在服务中使用 Websocket?

Angular how to use Websocket inside a service?

是否有可能以某种方式监听服务内的 WebSocket,并通过监听来自套接字的消息然后将更改发送到我的其他组件(例如通过 observables)使该服务“反应式”?

它当然应该适用于不同的 tab/browser 个实例。

正确的模式是什么?如果我在另一个 angular 组件中使用该服务,我是否需要先以某种方式初始化它,或者是否足以在我的组件中导入依赖项,因为服务中没有 ngOnInit 方法?

我可能会在服务构造函数中创建我的套接字侦听器,然后使用可观察对象创建下一个新事件。但是,不确定具体如何。!

是的,可以在服务中监听 WebSocket 并通过 Observables 通知组件收到的消息。

在我看来,这是 Observables 的一个非常自然的用例。

您可以在启动应用程序时打开 websocket 连接,如果它是 root 中提供的服务,您可以在不同组件之间共享相同的服务实例。

这个函数 returns 一个 Observable,它在打开 websocket 连接时通知 WebSocket 的实例

function openSocket$(url: string) {
  return new Observable(
    (subscriber: Subscriber<WebSocket>): TeardownLogic => {
      const conn = new WebSocket(url);
      conn.onopen = () => {
        subscriber.next(conn);
        subscriber.complete();
      };
      conn.onerror = (err) => {
        console.error("Websocket errored while trying to connect", err);
        subscriber.error(err);
      };
      conn.onclose = (ev) => {
        console.log("Websocket closed before having emitted any message");
        subscriber.complete();
      };
    }
  );
}

这个函数需要一个 WebSocket 的实例作为输入和 returns 一个 Observable 来通知在 websockets 通道上收到的每条消息:

function messages$(socket: WebSocket) {
  // if the onmessage property is defined, it means that this websocket is already in use by
  // some component which is interested in its message stream
  if (socket.onmessage) {
    throw new Error(
      "Websocket has already a function set to manage the message stream"
    );
  }
  return new Observable(
    (subscriber: Subscriber<MessageEvent>): TeardownLogic => {
      socket.onmessage = (msg: MessageEvent) => {
        subscriber.next(msg);
      };
      socket.onerror = (err) => {
        console.error("Websocket errored while sgreaming messages");
        subscriber.error(err);
      };
      socket.onclose = () => {
        console.log("Websocket closed");
        subscriber.complete();
      };
      return () => {
        // clean the onmessage callback when the Observable is unsubscribed so that we can safely check
        // whether the onmessage callback is null or undefined at the beginning of this function
        socket.onmessage = null;
      };
    }
  );
}

您可以查看使用此机制的应用示例 here

对于 angular's scope/zone 之外的任何图书馆筹集活动,最好的办法是将其纳入 scope/zone。

这样您就不需要考虑与 angular 生命周期事件的任何进一步同步。

我通常在服务中使用 Subject or ReplaySubject 来确保所有组件都能侦听引发的事件。

@Injectable()
export class YourService {
  eventType1$ = new Subject()
  constructor(private ngZone: NgZone ... 


...
   socketObject.onEventType1((eventType1) => {
      this.ngZone.run(() => {
        this.eventType1$.next(eventType1)
      });
   })

然后您可以从您的组件中正常订阅此服务的 public observable:

  yourComponentFunction() {
    this.yourService.eventType1$.subscribe((eventType1) => {
       // do something with eventType1
    })
  }

注意:请记得在组件销毁时完成任何订阅,避免常见的memory leak.