安全取消订阅可选的控制器订阅

Safe unsubscribing to optional controller subscriptions

是否有取消订阅控制器中所有现有但可能未初始化的订阅的确认且优雅的习惯用法?考虑以下代码段:

/* 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 */
  }
}

基本上肯定有一些直接的方法,比如心爱的 ifology:

  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 以外的其他控制器生命周期时刻选择性地取消订阅选定的订阅。

你可以这样做:

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

}

为什么不使用 takeUntil RxJs 运算符?

您可以订阅您想要的 Observable,等待 takeUntil 运算符在另一个 Observable 发出时取消订阅 Observable 链:

您可以将新的 Observable 声明为 Subject:

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 Angular 生命周期挂钩上):

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

此外,这是 RxJs 中的推荐结束模式,用于销毁您的订阅!您可以阅读有关 takeUntil 运算符 here.

的更多信息

您可以使用 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();
}