Angular 8 - 从两个不同的组件订阅一项服务

Angular 8 - subscribe to one service from two different components

我有一个 angular 服务和两个使用此服务的不同的不相关组件:

服务代码:

const url = 'ws://localhost:8080

@Injectable({
   provideIn: 'root',
})

export class MyService{

  public subject: Subject<Status>;

  constructor(wsService: WebSocketService){
    this.subject = <Subject<Status>>wsService.connect(url).map(
       (response: MessageEvent): Status => {
          let data = JSON.parse(response.data);
          return data;
        }
    );
  }

  getObs(){
    return this.subject.asObservable();
  }

  sendMsg(msg){
    this.subject.next(msg);
  }

}

组件 1:

@Component

.. some irrelevant code ..

constructor(private service: MyService){
  this.service.getObs().subscribe( data => 
    console.log('comp1');
  );

  console.log('comp1 - after subscribe');
}

.. some irrelevant code ..

组件 2:

@Component

.. some irrelevant code ..

constructor(private service: MyService){
  this.service.getObs().subscribe( data => 
    console.log('comp2');
  );

  console.log('comp2 - after subscribe');
}

.. some irrelevant code ..

我在控制台中得到以下输出:

comp1

comp1 - 订阅后

comp2 - 订阅后

我认为我应该得到的输出:

comp1

comp1 - 订阅后

comp2

comp2 - 订阅后

谁能解释一下问题出在哪里?

注意:我将我的服务添加到模块提供程序并得到了相同的结果。

谢谢。

这是 webSocketService 的代码:https://github.com/elliotforbes/ng-chat/blob/master/src/app/common/services/websocket.service.ts

您可以使用行为主题而不是普通主题。

https://medium.com/@luukgruijs/understanding-rxjs-behaviorsubject-replaysubject-and-asyncsubject-8cc061f1cfc0

您应该控制自己的主题,而不是依靠 WebSocketService.connect 并假设您将获得所需的行为。

从您发布的link到WebSocketService的源代码,我们看到它是一个普通的主题。 ReplaySubject.

提供了您想要的功能——在订阅时发出一个值(假设存在)

您应该声明一个本地 ReplaySubject,这是您的组件将订阅的内容。然后您将订阅您的 WebSocketService。来自 WebSocketService 的任何回复都将映射到一个状态,然后发送到您的本地主题。

const url = 'ws://localhost:8080

@Injectable({
   provideIn: 'root',
})

export class MyService{

  // Declare local ReplaySubject that emits the last value upon subscription
  private subject: Subject<Status> = new ReplaySubject<Status>(1);

  constructor(wsService: WebSocketService) {
    // Subscribe to the web socket service.
    // Subscribing in constructors is fairly bad practice, 
    // although you can get away with it in singleton services
    wsService.connect(url).pipe(
      // map responses to statuses
      map((response: MessageEvent): Status => {
        let data = JSON.parse(response.data);
        return data;
      })
    ).subscribe((status: Status) => {
      // send the status to all subscribers
      this.subject.next(status);
    });
  }

  getObs(): Observable<Status> {
    return this.subject.asObservable();
  }

  sendMsg(msg): void {
    this.subject.next(msg);
  }
}