取消订阅 Rxjs Observables

Posted

技术标签:

【中文标题】取消订阅 Rxjs Observables【英文标题】:Unsubscribing to Rxjs Observables 【发布时间】:2020-10-28 09:07:33 【问题描述】:

我开始使用一个使用 Rxjs observables 的遗留 angular 6 应用程序。组件中的可观察对象似乎没有使用我所看到的取消订阅。 ngOnInit 中的订阅示例:

this.service.getCustomerDetail(customers).subscribe(
          (data) => 
            this.customerData = data;
          ,
          () => 
            this.notify.addNotification(
              new notification(
                `Error retrieving customer data`
              )
            );
          
        );

订阅者正在使用完成,即使其中没​​有任何内容,即 Rxjs 订阅的 Next、Error、Complete 值,但在我看来,它需要将这些推送到订阅中,然后在 ngOnDestroy 上取消订阅所有这些。即使完整在可观察对象内,这些没有取消订阅的订阅也会留在堆内存中,也就是导致内存泄漏,这是正确的吗?

在我的订阅使用错误和完整部分的情况下,我是否会使用 TakeUntil 方法,例如:

this.service.getCustomerDetail(customers)
.pipe(takeUntil(this.ngUnsubscribe))
.subscribe(
          (data) => 
            this.customerData = data;
          ,
          () => 
            //error section
            this.notify.addNotification(
              new notification(
                `Error retrieving customer data`
              )
            );
          ,
          () => 
            //complete section
            this.loadAddlDetail();
          
        );

感谢您提供这方面的任何信息。

【问题讨论】:

takeUntil 方法是首选的角度解决方案***.com/questions/38008334/… @AdrianBrand 在描述中添加了一个问题,例如如果我已经有一个错误并完成订阅部分,我会使用 takeUntil 吗? 【参考方案1】:

您可以使用 ngOnDestroy() 并在其中添加 unsubscribe(),如下所示

ngOnDestroy() 
 if(serviceSubscription != null)
  serviceSubscription.unsubscribe();
  

或者您可以在 html 模板本身上使用异步管道,这样您就不必像下面那样手动取消订阅。

<p> observable | async </p>

【讨论】:

如果您的问题得到解决,请接受答案。谢谢 因此,例如,订阅点击了一个 http get,并将该数据加载到一个持久化和使用的对象数组中。在未添加取消订阅的情况下会发生什么情况是回调在堆上一直作为分配的内存直到它被销毁? 我也在考虑使用 TakeUntil,但是当它在 Next 中返回时没有服务 http 调用我将它设置为一个对象数组然后我有错误和完整的订阅区域.如果没有错误是混淆的地方,是否不会自动调用完整的。例如,如果我在 ngOnDestroy 上添加 TakeUntil,它也会调用 complete 和 next。【参考方案2】:

有两种方法可以做到这一点。如果这是一个孤立的案例,以下就足够了

方法 1 - 如果这是一个孤立的案例

------------------------------------------ --------

课堂上

更改类声明以包含OnDestroy

export class AppComponent implements OnInit, OnDestroy

添加私有变量来存储订阅

private serviceSubscription  = null

在 ngOnInit 中

this.serviceSubscription = this.service.getCustomerDetail(customers).subscribe(
      (data) => 
        this.customerData = data;
      ,
      () => 
        this.notify.addNotification(
          new notification(
            `Error retrieving customer data`
          )
        );
      
    );

实施 OnDestroy

ngOnDestroy() 
   if (this.serviceSubscription != null) 
     this.serviceSubscription.unsubscribe()
   
 

------------------------------------------ --------------

方法 2 - 如果在多个地方看到这种情况

------------------------------------------ --------------

为组件component-base.ts创建基类

import  Subscription  from 'rxjs';
import  OnDestroy  from '@angular/core';

export class ComponentBase implements OnDestroy 
    private subscriptions: Subscription[] = [];

    protected rxs(s: Subscription): void 
        this.subscriptions.push(s);
    

    ngOnDestroy() 
        this.subscriptions.forEach(x => x.unsubscribe());
    

ComponentBase扩展组件

export class AppComponent extends ComponentBase implements OnInit

在 ngOnInit 中

ngOnInit() 
    this.rxs(this.service.getCustomerDetail(customers).subscribe(
        (data) => 
        this.customerData = data;
        ,
        () => 
        this.notify.addNotification(
            new notification(
            `Error retrieving customer data`
            )
        );
        
    ));

【讨论】:

非常感谢,感谢您的反馈和示例。 Angular 的标准方法是使用 takeUntil 和单个主题来完成所有可观察对象或使用异步管道。订阅数组不是一个好的解决方案。 谢谢阿德里安,我正在调查 @AdrianBrand 如果我的订阅在第 3 部分已经有一个完整的部分,也就是我有一个获取数据的下一个部分,错误然后是一个调用其他一些方法的完整部分。在这种情况下,我应该使用将在 ngOnDestroy 上调用 .next 和 .complete 的 TakeUntil 吗?

以上是关于取消订阅 Rxjs Observables的主要内容,如果未能解决你的问题,请参考以下文章

任何需要先取消订阅 RxJS()

取消 rxjs 中的 http 订阅

RxJS 迁移 5 到 6 - 使用 TakeUntil 取消订阅

取消订阅 Rxjs Observables

RxJS迁移5到6 - 取消订阅TakeUntil

Angular + RxJS:使用 takeUntil 与简单取消订阅?