可观察的角度-如果没有订阅,我需要取消订阅吗?

时间:2019-10-19 03:26:14

标签: angular rxjs observable

我正在使用最新的angular 8,对可观察物的概念还是陌生的。我有一个问题,如果我直接调用可观察对象而不将其应用于订阅变量,我是否仍需要取消订阅。以下是我想知道是否需要取消订阅的情况? 提前非常感谢

方案1-从组件调用httpService:

Service - httpService

     getContactsHttp(){
         let headers: any = new HttpHeaders(this.authService.getHeadersClient());
         return this.httpClient.get('/contacts', {headers: headers})
          .pipe(timeout(this.authService.getTimeoutLimit('normal')));
        }

Component - Calling getContactsHttp and sorting response

getContacts() {
 this.httpService.getContactsHttp().subscribe((data:any[])=>{
  this.records = this.sortData(data)
 })
}

方案2-组件中的可观察物

contacts$: new Subject<any[]>;

ngOnInit() {
  this.getContacts();
  this.contacts$.subscribe((data:any[])=>{
    this.records = this.sortData(data);
  })
}

getContacts() {
    this.httpService.getContactsHttp().subscribe((data:ContactSearch[])=>{      
      this.contacts$.next(data);
    })
  }

服务-httpService

     getContactsHttp(){
         let headers: any = new HttpHeaders(this.authService.getHeadersClient());
         return this.httpClient.get('/contacts', {headers: headers})
          .pipe(timeout(this.authService.getTimeoutLimit('normal')));
        }

5 个答案:

答案 0 :(得分:2)

简短的回答,是的,您仍然取消订阅avoid subscription leaks中的可观察对象。我这样做的首选方式之一是利用takeUntil()运算符。

这是在组件中使用它的方式。

private unsubscribe: Subject<void> = new Subject();

ngOnDestroy() {
  this.unsubscribe.next();
  this.unsubscribe.complete();
}

getContacts() {
  this.httpService.getContactsHttp()
    .pipe(
      takeUntil(this.unsubscribe),
    ).subscribe((data:ContactSearch[])=>{      
      this.contacts$.next(data);
    });
 }

Brian Love所述,

  
      
  • 首先,我们导入takeUntil()运算符以及Subject   类。
  •   
  • 接下来,我们定义一个名为unsubscribe的私有实例属性,   这是一个主题。
  •   
  • 我们还创建了一个Subject的新实例,   通用类型为void。我们在   在调用subscribe()之前提供pipe()方法,提供取消订阅   可观察的。
  •   
  • 在ngOnDestroy()生命周期方法中,我们发出next()   通知,然后完成()取消订阅的观察。的   订阅现已完成,我们已立即取消订阅   在我们的生命周期中调用ngOnDestroy()方法时   组件。
  •   

答案 1 :(得分:2)

1)通常,直接拨打http呼叫时无需取消订阅。即使该组件被销毁,销毁后完成预订的开销也是微不足道的。 如果要快速切换组件,则需要在此处退订。取消订阅也会取消http请求,因此,如果需要,可以取消订阅。

退订不会造成任何伤害。如果不确定,请务必退订。

2)当您订阅一个可观察物时,您确实需要退订该可观察物,该可观察物在您的作曲品被破坏后还没有完成。否则,这将导致内存(和性能)泄漏。因为可观察对象本身持有对预订的引用,而预订包含对组件的引用,所以该组件将永远不会从内存中清除,并且预订中描述的操作将一直运行,直到可观察对象完成为止(在您的情况下,这永远不会发生) 。这将在您组件的每个实例中发生。

解决方案

在简化取消订阅的负担方面,我将分享两个常用的选项。扩展@ amanagg1204答案,您可以创建一个基础组件,并从中扩展所有将来的组件。您可以在其中包含一个自定义运算符。这样做有一个缺点-如果需要在组件中使用super.ngOnDestroy(),则必须始终调用ngOnDestroy

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

export abstract class UnsubscribeComponent implements OnDestroy {
  protected destroyed$: Subject<void> = new Subject();

  ngOnDestroy(): void {
    this.destroyed$.next();
    this.destroyed$.complete();
  }

  takeUntilDestroyed<T>(): MonoTypeOperatorFunction<T> {
      return takeUntil(this.destroyed$);
  }
}

export class Component extends UnsubscribeComponent {
   ngOnInit() {
      this.contacts$.pipe(
              this.takeUntilDestroyed(),
          ).subscribe((data:any[])=>{
          this.records = this.sortData(data);
      });
   }

  // WARNING - if you declare your ngOnDestroy in the component
  ngOnDestroy() {
     // DO NOT FORGET to call this
     super.ngOnDestroy();
     doYourStuff();
  }

}

其他选择(我更喜欢)不是拥有父抽象类(尽管也可以这样实现),而是使用名为subsinknpm i subsink --save)的实用程序

import { SubSink } from 'subsink';

export class SampleComponent implements OnInit, OnDestroy {
  private subs = new SubSink();

  ngOnInit(): void {
    // Just put it into sink.
    this.subs.sink = this.contacts$.subscribe((data:any[])=>{
      this.records = this.sortData(data);
    });
    // call repeatedly
    this.subs.sink = this.otherService$.subscribe((data:any[])=>{
      this.things = this.sortData(data);
    });
  }

  ngOnDestroy(): void {
    // this will unsubscribe all
    this.subs.unsubscribe();
  }
}

答案 2 :(得分:1)

正如许多人已经指出的那样,http返回了一个冷的Observable,但是您仍然应该从该Observable退订。我将建议一种更好的管理退订的方法,这样您就不必手动添加ngOnDestroy()生命周期挂钩。 我将从创建一个如下所示的退订组件开始

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

export abstract class UnsubscribeComponent implements OnDestroy {
  protected destroyed$: Subject<void> = new Subject();

  ngOnDestroy(): void {
    this.destroyed$.next();
    this.destroyed$.complete();
  }
}

然后在每个组件类声明中进行扩展(如有需要)

export class ABC extends UnsubscribeComponent

在构造函数中调用super()

constructor(your dependencies) {
  super()
}

最后是您的订阅,请执行以下操作

this.obs$.pipe(takeUntil(this.destroyed$)).subscribe(() => {
  // some logic here
})

另一件事是takeUntil应该是管道中的最后一个运算符。希望对您有帮助。

答案 3 :(得分:0)

是的,取消订阅ngOnDestroy生命周期方法中的所有订阅是一种很好的做法,您可以通过在类级别变量中引用每个订阅的引用然后手动取消订阅来做到这一点!

答案 4 :(得分:0)

是的,总是退订。您有多种退订方式,如下所示:

-使用takeUntil()

-take(1)

-unsubscribe()ngOnDestroy()

-使用async管道

是的,httpClient返回一个可观察到的冷现象,但是这个问题将向您解释为什么您仍然应该unsubscribe。 (看看投票数最高的第二个答案)

Is it necessary to unsubscribe from observables created by Http methods?

https://blog.angularindepth.com/why-you-have-to-unsubscribe-from-observable-92502d5639d0

在旁注:

1)切勿订阅该服务。我们处在Angular世界中,我们需要以一种被动的方式进行思考,在服务中购买订阅会阻止您在希望将其与其他内容结合使用时使用可观察的结果。

2)处理可观察对象时,开始使用声明式方法。

3)停止使用any,这不是一个好习惯。通过使用类和接口,您的代码将更具可读性。

声明式方法的好处: -利用RxJ的可观察者和操作者的力量 -有效地合并流 -易于观察的份额 -随时响应用户操作

您可能想知道声明式方法的外观如何?

您将无需执行返回可观测值的方法,而是执行此操作。

SERVICE.TS

  yourObservableName$ = this.httpClient.get('/contacts', {headers: headers})
              .pipe(timeout(this.authService.getTimeoutLimit('normal')));

COMPONENT.TS

this.httpService.yourObservableName$.subscribe(...)