提问者:小点点

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')));
        }

共3个答案

匿名用户

简而言之,是的,您仍然取消订阅组件中的可观察对象以避免订阅泄漏。我更喜欢这样做的方法之一是使用带直到()运算符。

这就是您可以在组件中使用它的方式。

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

正如布莱恩·洛夫所解释的,

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

匿名用户

1)通常,直接调用超文本传输协议调用时不需要取消订阅。即使组件被销毁,销毁后订阅完成的开销也不大。如果快速切换组件,您需要在此取消订阅。取消订阅也会取消超文本传输协议请求,所以如果需要,请取消订阅。

退订没有任何坏处。如果你不确定,总是退订。

2)当订阅一个在组件被销毁时未完成的可观察对象时,您确实需要取消订阅。否则这将导致内存(和性能)泄漏。因为可观察对象本身持有对订阅的引用,而订阅持有对组件的引用,所以组件永远不会从内存中清除,订阅中描述的操作将一直运行,直到可观察对象完成,在您的情况下,这永远不会发生。这将发生在您的组件的每个实例中。

我将分享两个简化退订负担的流行选项。扩展@amanagg1204答案,您可以创建一个基础组件,从中扩展所有未来的组件。您可以在其中使用自定义运算符。这有一个缺点——如果您需要在组件中使用ngOnDestroy,您总是必须调用super. 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();
  }

}

其他选择(我的首选)不是有一个父抽象类(尽管它也可以这样实现),而是使用一个名为subink的实用程序(npm i subink--sav

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

匿名用户

是的,始终取消订阅。您有多种取消订阅的方式,如下所示:

-使用带直到()

-取(1)

-在ngOnDestroy()中取消订阅()

-使用async管道

是的,httpClient返回一个冷可观察值,但这个问题将解释为什么您仍然应该取消订阅。(看看投票最高的第二个答案)

是否有必要取消订阅由Http方法创建的可观察对象?

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

在旁注:

1)永远不要在服务中订阅。我们在Angular世界中,我们需要以被动的方式思考,在服务中购买订阅会阻止你使用那个可观察的东西,以防你想把它和其他东西结合起来。

2)在使用可观察对象时开始使用声明性方法。

3)停止使用任何,这不是好的做法。使用类和接口,这样你的代码会更具可读性。

声明式方法的好处:-利用RxJs可观察对象和运算符的强大功能-有效组合流-轻松共享可观察对象-随时对用户操作做出反应

你可能想知道声明式方法是什么样的?

您将执行此操作,而不是使用返回可观察对象的方法。

服务. TS

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

组件. TS

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