Безопасная отмена подписки на дополнительные контроллеры - PullRequest
1 голос
/ 25 марта 2019

Существует ли подтвержденная и элегантная идиома отказа от подписки на все существующие, но, возможно, не инициализированные подписки в контроллере?Рассмотрим следующий фрагмент:

/* Somewhere on init */
if(/* condition 1 */) {
  this.subscription1 = this.service1().subscribe();
}

if(/* condition 2 */) {
  this.subscription2 = this.service2().subscribe();
}

И на этапе очистки:

onDestory() {
  try{
    this.subscription1.unsubscribe();
    this.subscription2.unsubscribe();
  } catch e {
    /* One of subscriptions was uninitialized */
    /* If that was first one, second may be left unsubscribed */
  }
}

В принципе, есть некоторые из простых методов, таких как любимая ифология:

  if(this.subscription1) {
  this.subscription1.unsubscribe();
  }
  if(this.subscription2) {
    this.subscription2.unsubscribe();
  }

использование массива подписок вместо полей контроллера:

/* Somewhere on init */
if(/* condition 1 */) {
  this.subscriptions.push(this.service1().subscribe())
}

if(/* condition 2 */) {
  this.subscriptions.push(this.service2().subscribe())
}

  noDestroy() {
    this.subscriptions.forEach(s => s.unsubscribe();)
  }

Но, может быть, есть некоторые аккуратные и надежные способы решения такой задачи?Согласно моему опыту, ifology является утомительной для сохранения и ее легко забыть обновить, в то время как на основе массива список подписок становится неуправляемым в случае, если вы хотите выборочно отказаться от подписки на выбранную подписку в момент жизненного цикла контроллера, отличный от onDestroy.

Ответы [ 3 ]

3 голосов
/ 25 марта 2019

Почему бы не использовать оператор takeUntil RxJs?

Вы можете подписаться на нужные вам наблюдаемые, ожидая, пока оператор takeUntil откажется от цепочки наблюдаемых, когда другая Наблюдаемая выдаст:

Вы можете объявить свой новый объект наблюдения как субъект:

private destroySubscriptions$ = new Subject<void>();
/* Somewhere on init */
if(/* condition 1 */) {
  this.service1()
    .pipe(
      takeUntil(this.destroySubscriptions$)
    ).subscribe();
}

if(/* condition 2 */) {
  this.service2()
    .pipe(
      takeUntil(this.destroySubscriptions$)
    ).subscribe();
}

И на этапе очистки (обычно на onDestroy Угловом крюке жизненного цикла):

ngOnDestroy() {
  this.destroySubscriptions$.next();
}

Кроме того, это рекомендуемый шаблон в RxJ для уничтожения ваших подписок! Подробнее об операторе takeUntil можно прочитать здесь .

2 голосов
/ 25 марта 2019

Вы можете использовать takeUntil :

import { OnDestroy, OnInit } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';


export class MyComponent implements OnInit, OnDestroy {

 private readonly ngUnSub: Subject<void>;


constructor() {
  this.ngUnSub = new Subject<void>();
}

public ngOnInit(): void {

  if (condition1) {
   this.service1.pipe(takeUntil(this.ngUnSub)).subscribe();
  }

  if (condition2) {
   this.service2.pipe(takeUntil(this.ngUnSub)).subscribe();
  }
}

public ngOnDestroy(): void {
  this.ngUnSub.next();
  this.ngUnSub.complete();
}
1 голос
/ 25 марта 2019

Вы можете сделать это:

import { Subscription } from 'rxjs';

...

export class MyComponent implements OnInit, OnDestroy {

    private subscriptions: Subscription[] = [];
  
    ...
  
  
    ngOnDestroy() {
        this.subscriptions.forEach(sub => sub.unsubscribe());
    }

    ....

    if(/* condition 1 */) {
        this.subscriptions.push(this.service1().subscribe());
    }

    if(/* condition 2 */) {
        this.subscriptions.push(this.service2().subscribe());
    }

}
...