如何取消订阅角度组件中的多个可观察对象?

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();

【讨论】:

以上是关于如何取消订阅角度组件中的多个可观察对象?的主要内容,如果未能解决你的问题,请参考以下文章

我试图取消订阅一个可观察的角度但我收到错误,例如取消订阅不存在

如何取消订阅路由解析类中的可观察对象

我们是不是需要取消订阅完成/错误输出的可观察对象?

取消订阅 Rxjs Observables

可观察,在 ngOnDestroy 中取消订阅不起作用

React 如何订阅在另一个组件中声明的可观察对象