简体   繁体   English

Angular 2:BehaviorSubject,避免多重订阅

[英]Angular 2: BehaviorSubject, avoid with multiple subscription

Hi I have following problem in my Angular 2 app.您好,我的 Angular 2 应用程序出现以下问题。

I have BroadcastService :我有广播服务

@Injectable()
export class BroadcastService {

   private broadcastSubject: BehaviorSubject<Event> = new BehaviorSubject<Event>(0);

   public next(event: Event): void {
     return this.broadcastSubject.next(event);
   }

   public subject(event: Event): Observable<Event> {
     return this.broadcastSubject.asObservable().filter(e => e === event);
   }
 }

Which I use in components like this:我在这样的组件中使用:

export class MyComponent implements OnInit {

   constructor(public broadcastService: BroadcastService) {
     this.broadcastService.subject(Event.BLA_EVENT).subscribe(() => this.bla());
   }
...

Whenever I route to '/mycomponent' the MyComponent.constructor is called, so the Event.BLA_EVENT is subscriped multiple times.每当我路由到 '/mycomponent' 时,都会调用 MyComponent.constructor,因此会多次订阅 Event.BLA_EVENT。

Any advice how to prevent multiple time subscription?关于如何防止多次订阅的任何建议?

Manual subscriptions inside components should always be unsubscribed in the ngOnDestroy hook. 组件内部的手动订阅应始终在ngOnDestroy挂钩中取消订阅。 This is to prevent memory leaks, unwanted double subscriptions, and errors occuring if you change something inside the component after it has been destroyed: 这是为了防止内存泄漏,不必要的双重订阅以及在销毁组件后更改组件内部内容时发生的错误:

export class MyComponent implements OnInit, OnDestroy {

   private _broadSub;

   constructor(public broadcastService: BroadcastService) {}

   ngOnInit() {
      this._broadSub = this.broadcastService.subject(Event.BLA_EVENT).subscribe(() => this.bla());
   }

   ngOnDestroy() {
       this._broadSub.unsubscribe();
   }

}

I had a similar problem and I solved it by checking the quantity of the observers on the event. 我有一个类似的问题,我通过检查事件观察者的数量来解决。 The option using ngOnDestroy may be the best, but another approach could be something like: 使用ngOnDestroy的选项可能是最好的,但是另一种方法可能是:

constructor(public broadcastService: BroadcastService) {
    if(this.broadcastService.subject(Event.BLA_EVENT).observers.length == 0) {
        this.broadcastService.subject(Event.BLA_EVENT).subscribe(() => this.bla());
    }
}

Now you can use BroadcastChannel in almost all browsers (see caniuse):现在您可以在几乎所有浏览器中使用 BroadcastChannel(请参阅 caniuse):

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class BroadcastService {
  private consumer: BroadcastChannel;
  private producer: BroadcastChannel;

  constructor() {
    this.consumer = new BroadcastChannel('pluginGlobalEventBus');
    this.producer = new BroadcastChannel('pluginGlobalEventBus');
  }

  postMessage(message: any): void {
    this.producer.postMessage(message);
  }

  addEventListener(eventName, listener): void {
    this.consumer.addEventListener('message', event => {
      if (event.data.name === eventName) {
        listener(event.data.value);
      }
    });
  }
}

export class EmitEvent {
  constructor(public name: any, public value?: any) {}
}

usage:用法:

// sending
const event = new EmitEvent('logEvent', 'BUTTON_CLICKED');
this.broadcastService.postMessage(event);


// listening
this.broadcastService.addEventListener('logEvent', (interaction: string) => {
  console.log(interaction)
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM