Angular observables - нужно ли отписываться, если нет подписки? - PullRequest
3 голосов
/ 19 октября 2019

Я использую последний угловой 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 ]

2 голосов
/ 19 октября 2019

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

}

Другой вариант (мой предпочтительный) - не иметь родительский абстрактный класс(хотя это также может быть реализовано так), но использовать утилиту под названием subsink (npm 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 голосов
/ 19 октября 2019

Короткий ответ, да, вы все еще отмените подписку на свои наблюдаемые в своем компоненте, чтобы избежать утечек при подписке . Один из моих предпочтительных способов сделать это - использовать оператор 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);
    });
 }

Как объяснили Брайан Лав ,

  • Сначала мы импортируем оператор takeUntil (), а также класс Subject.
  • Далее мы определяем частное свойство экземпляра с именем unsubscribe, которое является Subject.
  • Мы также создаем новый экземпляр Subject, определяя универсальный тип как void. Мы используем оператор takeUntil () в методе pipe () перед вызовом subscribe (), обеспечивая наблюдаемую отмену подписки.
  • В методе жизненного цикла ngOnDestroy () мы отправляем уведомление next (), а затем завершаем () наблюдаемую отмену подписки. Подписка завершена, и мы немедленно отменили подписку, когда метод ngOnDestroy () вызывается в течение жизненного цикла нашего компонента.
1 голос
/ 19 октября 2019

Как уже отмечали многие, http возвращает Cold 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 должен быть последним оператором в конвейере. Надеюсь, это поможет вам.

0 голосов
/ 19 октября 2019

Да, всегда отписываться. У вас есть несколько способов отписаться, а именно:

- использование takeUntil()

- take(1)

- unsubscribe() в ngOnDestroy()

- с использованием async pipe

Да, httpClient возвращает наблюдаемую холодность, но этот вопрос объяснит вам, почему вы все еще должны unsubscribe. (посмотрите на второй ответ с наибольшим количеством голосов)

Нужно ли отписываться от наблюдаемых, созданных методами Http?

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

На примечании стороны:

1) Никогда не подписывайтесь на услугу. Мы находимся в мире Angular, и нам нужно мыслить реактивно, покупка подписки в сервисе не позволяет вам использовать это наблюдаемое в случае, если вы хотите объединить его с чем-то другим.

2) Начните использоватьдекларативный подход при работе с наблюдаемыми.

3) Прекратить использование any, это не очень хорошая практика. Используйте классы и интерфейсы, благодаря чему ваш код будет более читабельным.

Преимущества декларативного подхода: -Используйте возможности наблюдаемых и операторов RxJs -Эффективно объединяйте потоки -Просто разделяйте наблюдаемые -Объекты -Быстро реагируйте наuser action

Возможно, вам интересно, как выглядит декларативный подход?

Вместо того, чтобы иметь методы для возврата наблюдаемых, вы собираетесь это сделать.

SERVICE.TS

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

COMPONENT.TS

this.httpService.yourObservableName$.subscribe(...)
0 голосов
/ 19 октября 2019

Да, рекомендуется отписаться от всех подписок в методе жизненного цикла ngOnDestroy, вы можете сделать это, взяв ссылку на каждую подписку в переменной уровня класса, а затем отписавшись от них вручную!

...