如何取消订阅角度组件中的多个可观察对象?
Posted
技术标签:
【中文标题】如何取消订阅角度组件中的多个可观察对象?【英文标题】:How to unsubscribe multiple observables in angular component? 【发布时间】:2019-08-20 09:50:12 【问题描述】:取消订阅多个角度观察的最佳策略是什么?需要明确的是,当应用程序不大并且不需要像 ngrx 这样的解决方案时,我会使用这种方法,在这种情况下会是 过度工程.
目前我使用订阅实例来添加所有订阅,然后当组件被销毁时我调用取消订阅方法。但我也看到了使用 rxjs 中的 takeUntil 的替代方法。
export class MyComponent implements OnInit, OnDestroy
$firstObservable: Observable<number> = timer(0, 1000);
$secondObservable: Observable<number> = timer(0, 1000);
private _subscriptions = new Subscription();
constructor()
ngOnDestroy(): void
this._subscriptions .unsubscribe();
ngOnInit(): void
this._subscriptions .add(
this.$firstObservable.subscribe(console.log));
this._subscriptions .add(
this.$secondObservable.subscribe(console.log));
最好的解决方案是什么?
【问题讨论】:
您可以将所有这些订阅合并到一个.subscribe
takeUntil
目前被认为是最佳实践。
使用takeUntil
是最简单的方法。顺便说一句,您可以链接 this._subscriptions.add().add().add()
调用,这样会更短一些。
【参考方案1】:
我建议你使用takeUntil()
pipeable 运算符:https://www.learnrxjs.io/operators/filtering/takeuntil.html
这样,您创建了一个Subject
,它将在ngOnDestroy
上发出值并一次取消订阅多个订阅
unsubscribeSignal: Subject<void> = new Subject();
$firstObservable: Observable<number> = timer(0, 1000);
$secondObservable: Observable<number> = timer(0, 1000);
ngOnInit()
this.$firstObservable
.pipe(
takeUntil(this.unsubscribeSignal.asObservable()),
)
.subscribe(result => );
this.$secondObservable
.pipe(
takeUntil(this.unsubscribeSignal.asObservable()),
)
.subscribe(result => );
ngOnDestroy()
this.unsubscribeSignal.next();
// Don't forget to unsubscribe from subject itself
this.unsubscribeSignal.unsubscribe();
【讨论】:
您可以在我在上一个答案中分享的链接中看到。使用 takeUntil 运算符时必须小心。 “我们不应该忘记 takeUntil 运算符必须是管道中的最后一个运算符(通常)以防止后续运算符返回可能阻止清理的其他可观察对象的情况。- by Brian Love”。【参考方案2】:我很失望人们甚至没有提到async
管道。
它非常强大,让您无需担心订阅问题并使用推送检测策略。
要使用它,只需从您的 TS 中删除订阅,并将值分配给您的变量,这些变量将被键入为 observables。
只看代码精简和简洁(不知道是不是一个词,但有点不在意)
export class MyComponent
firstObservable$: Observable<number> = timer(0, 1000);
secondObservable$: Observable<number> = timer(0, 1000);
combination$ = combineLatest(this.firstObservable$, this.secondObservable$)
.pipe(tap(() => console.log()));
在你的 HTML 中
<ng-container *ngIf="combination$ | async">
Observables are being observed.
</ng-container>
(尽管它不适合您的问题示例,但您已经可以看到它是如何更清洁和更简单的)
最好的一点是,您不必再担心内存泄漏。 Angular 负责所有订阅,让您只关心您的代码(这是一个好的框架应该做的)。
【讨论】:
是的,异步管道非常强大。但有些情况需要手动订阅。 @RenatoSantos 然后提供这些案例,而不是这样的例子! @trichetriche 我刚刚发布了一个答案,其中我指的是显示所有场景的帖子。【参考方案3】:最简单的方法是存储subscribtion
对象并在ngDestory
上调用取消订阅方法。
export class MyComponent implements OnInit, OnDestroy
$firstObservable: Observable<number> = timer(0, 1000);
$secondObservable: Observable<number> = timer(0, 1000);
private _subscriptions :any[] = [];
constructor()
ngOnDestroy(): void
this._subscriptions .unsubscribe();
ngOnInit(): void
this._subscriptions .push(
this.$firstObservable.subscribe(console.log)
);
this._subscriptions .push(
this.$secondObservable.subscribe(console.log)
);
ngOnDestroy()
this._subscriptions.forEach(sub => sub.unsubscribe()) ; // ?♂️?♂️
【讨论】:
【参考方案4】:Subscribe
类有一个 add
方法,可以将多个订阅合二为一,然后可以同时为 unsubscribed
。
subscription1 = observable.subscribe(
// next, err, complete etc
);
subscription2 = observable.subscribe(
// next, err, complete etc
);
添加多个订阅
subscription1.add(subscription2);
一次性取消所有订阅。
subscription1.unsubscribe();
【讨论】:
以上是关于如何取消订阅角度组件中的多个可观察对象?的主要内容,如果未能解决你的问题,请参考以下文章