Угловой лучший способ очистить подписки

Есть много способов эффективно обрабатывать несколько подписок в компоненте, у меня есть 2 способа здесь, и я хотел знать, какой из них более эффективен и почему?

Способ 1: использование массива

Шаг 1: создание массива

private subscriptionArray: Subscription[];

Шаг 2: Добавление подписок в массив

this.subscriptionArray.push(this._storeManagementHttp.createStore(newStore).subscribe(resp => {
  this._toast.success('New store created');
}));

Шаг 3: повторение каждой подписки и отмена подписки

this.subscriptionArray.forEach(subs => subs.unsubscribe());

Способ 2

Шаг 1: создание новой подписки

private subscriptions = new Subscription();

Шаг 2: Добавление подписок

this.subscriptions.add(this._storeManagementHttp.createStore(newStore).subscribe(resp => {
  this._toast.success('New store created');
  this._router.navigate(['/store-management']);
}));

Шаг 3: Очистка подписки

this.subscriptions.unsubscribe();

6 ответов

Вы также можете это, вам не нужно запускать цикл в этом случае

private destroy$ = new Subject();

myservice.megohd().pipe(takeUntil(destroy$)).subscribe();

ngOnDestroy() {
  this.destroy$.next();
  this.destroy$.complete();
}

читать здесь ( https://www.learnrxjs.io/operators/filtering/takeuntil.html)

У вас также есть третий вариант - пользовательский оператор RxJS.

Я создал один и узнал, что Нетанель Базаль тоже нашел его, поэтому я дам его чистый код.

Вы можете установить BeforeDestroyed или использовать код:

function isFunction(value) {
  return typeof value === 'function';
}

export const untilDestroyed = (
  componentInstance,
  destroyMethodName = 'ngOnDestroy'
) => <T>(source: Observable<T>) => {
  const originalDestroy = componentInstance[destroyMethodName];
  if (isFunction(originalDestroy) === false) {
    throw new Error(
      `${
        componentInstance.constructor.name
      } is using untilDestroyed but doesn't implement ${destroyMethodName}`
    );
  }
  if (!componentInstance['__takeUntilDestroy']) {
    componentInstance['__takeUntilDestroy'] = new Subject();

    componentInstance[destroyMethodName] = function() {
      isFunction(originalDestroy) && originalDestroy.apply(this, arguments);
      componentInstance['__takeUntilDestroy'].next(true);
      componentInstance['__takeUntilDestroy'].complete();
    };
  }
  return source.pipe(takeUntil<T>(componentInstance['__takeUntilDestroy']));
};

Тогда ваши подписки становятся

this.myService.subject.pipe(untilDestroyed(this)).subscribe(...);

Обратите внимание, что из-за компиляции AOT, вы должны написать ngOnDestroy метод, в противном случае оператор не может создать его с нуля.

Есть лучшее, более лаконичное решение: https://www.npmjs.com/package/subsink от Ward Bell.

      export class SomeComponent implements OnDestroy {
  private subs = new SubSink();

  ...
  this.subs.sink = observable$.subscribe(...);
  this.subs.sink = observable$.subscribe(...);
  this.subs.sink = observable$.subscribe(...);
  ...

  // Unsubscribe when the component dies
  ngOnDestroy() {
    this.subs.unsubscribe();
  }
}

Способ 2, потому чтоSubscription.unsubscribe()делает больше, чем просто кажущаяся отписка, см. его исходный код здесь .

например

      
class SomeClass implements OnInit, OnDestroy { {

  // Setup your subscriptions
  private subscriptions = new Subscription();

  // Example Observable service
  constructor(private someService: SomeService) {}

  ngOnInit(): void {
    this.subscriptions.add(this.someService.getStuff());
    // ...
    this.subscriptions.add(/* etc */);
  }

  ngOnDestroy() {
    this.subscriptions.unsubscribe();
  }

} 

У вас есть хорошие ответы, хотя я бы постарался избежать всех вышеперечисленных методов, если это возможно, и пошел бы на async'pipe, то есть разрешить angular выполнять подписку и отмену подписки.

Давайте рассмотрим несколько наблюдаемых, скажем, 5 наблюдаемых.

      observale1$: Observable<IDataDto1>;
observale2$: Observable<IDataDto2>;
observale3$: Observable<IDataDto3>;
observale4$: Observable<IDataDto4>;
observale5$: Observable<IDataDto5>;

Чтобы не подписываться на все это, мы можем создать один единственный Observableсказать v$

      
import { forkJoin } from 'rxjs';
v$ = forkJoin({
  observale1: observale1$,
  observale2: observale2$,
  observale3: observale3$,
  observale4: observale4$,
  observale5: observale5$
});

С помощью вышеизложенного мы можем обернуть наш component.html в *ngIfи разрешить angular автоматически подписываться и отписываться

      
<ng-container *ngIf='v$ | async as v'>
  <!-- Your html code here -->
</ng-container>

Я бы предпочел метод 2.

По методу 1 проблем нет.

Работает отлично. Проблема этого подхода в том, что мы смешиваем наблюдаемые потоки с простой старой императивной логикой.

Метод 2 является встроенным механизмом для улучшения этого подхода.

Читайте здесь

Другие вопросы по тегам