Подтвердить что ты не робот

Как отказаться от подписки на несколько подписчиков в angular 2

У меня есть shareService и подписаться, что есть в других компонентах:

import { Component, Input, OnDestroy } from '@angular/core';
import { MissionService } from './mission.service';
import { Subscription }   from 'rxjs/Subscription';
@Component({
  selector: 'my-astronaut',
  template: `
    <p>
      {{astronaut}}: <strong>{{mission}}</strong>
      <button
        (click)="confirm()"
        [disabled]="!announced || confirmed">
        Confirm
      </button>
    </p>
  `
})
export class AstronautComponent implements OnDestroy{
  @Input() astronaut: string;
  mission = "<no mission announced>";
  confirmed = false;
  announced = false;
  subscription:Subscription;

  constructor(private missionService: MissionService) {
    this.subscription = missionService.missionAnnounced$.subscribe(
      mission => {
        this.mission = mission;
        this.announced = true;
        this.confirmed = false;
    })




  }
  confirm() {
    this.confirmed = true;
    this.missionService.confirmMission(this.astronaut);
  }
  ngOnDestroy(){
    // prevent memory leak when component destroyed
    this.subscription.unsubscribe();

  }
}

Я хочу знать, есть ли у меня 2 подписчика в моем constructor, как отменить подписку на двух абонентов в ngDestroy? Я должен использовать subscription2:Subscription;? И в ngDestroy this.subscription2.unsubscribe();? это верно?

4b9b3361

Ответ 1

Вы можете собирать подписки, которые хотите отменить подписку сразу в ngOnDestroy() в массиве

export class AstronautComponent implements OnDestroy{
  @Input() astronaut: string;
  mission = "<no mission announced>";
  confirmed = false;
  announced = false;
  subscriptions:Subscription[] = [];

  constructor(private missionService: MissionService) {
    this.subscriptions.push(missionService.missionAnnounced$.subscribe(
      mission => {
        this.mission = mission;
        this.announced = true;
        this.confirmed = false;
    }));

    this.subscriptions.push(fooService.fooObservable$.subscribe(
      ...
    }));
  }

  confirm() {
    this.confirmed = true;
    this.missionService.confirmMission(this.astronaut);
  }

  ngOnDestroy(){
    // prevent memory leak when component destroyed
    this.subscriptions.forEach(s => s.unsubscribe());
  }
}

Ответ 2

Subscription может содержать дочерние подписки и безопасно отписываться от них всех. Этот метод обрабатывает возможные ошибки (например, если какие-либо дочерние подписки нулевые). Кроме того, если какие-либо подписки добавляются после ngOnDestroy, они будут немедленно отписаны.

Следует отметить, что Subscription.add() возвращает добавленную подписку. Таким образом, цепочка add() подобная subManager.add(sub1).add(sub2), добавит sub2 к sub1. Это будет проблемой, если sub1 ранее, так как он также sub2 от sub2.

import { OnDestroy } from "@angular/core";
import { Observable } from "rxjs/Observable";
import { Subscription } from "rxjs/Subscription";

export class MyComponent implements OnDestroy {
    ob1: Observable<number>;
    ob2: Observable<number>;
    subManager = new Subscription();

    constructor() {
        this.ob1 = Observable.interval(1000);
        this.ob2 = Observable.interval(2000);

        let sub1 = this.ob1.subscribe(val => console.log(val));
        let sub2 = this.ob2.subscribe(val => console.log(val));

        // DO NOT CHAIN add() - SEE ABOVE
        this.subManager.add(sub1);
        this.subManager.add(sub2);
    }

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

Из документации:

Кроме того, подписки могут быть сгруппированы с помощью метода add(), который присоединяет дочернюю подписку к текущей подписке. Когда подписка отменяется, все ее дочерние элементы (и ее внуки) также отписываются.

...

Если эта подписка уже находится в закрытом состоянии, переданная логика разрыва будет выполнена немедленно.

Ответ 3

На мой взгляд, более элегантным и универсальным (неважно, сколько у вас подписок) является использование операторов takeUntil из пакета rxjs.

import { OnDestroy } from "@angular/core";
import { Subject, Observable } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

export class MyComponent implements OnDestroy {

    ob1: any;
    ob2: any;

    private _endSubs: Subject<any> = new Subject();
    private endSubs$ = this._endSubs.asObservable();

    constructor() {
        this.ob1 = Observable.interval(1000);
        this.ob2 = Observable.interval(2000);

        let sub1 = this.ob1.pipe(takeUntil(this.endSubs$)).subscribe(val => console.log(val));
        let sub2 = this.ob2.pipe(takeUntil(this.endSubs$)).subscribe(val => console.log(val));

        .... (more subscriptions here)
    }

    ngOnDestroy() {
        this._endSubs.next();
    }
}