Как отказаться от подписки на несколько подписчиков в 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();
?
это верно?
Ответы
Ответ 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();
}
}