安全退订可选的控制器订阅

时间:2019-03-25 10:44:17

标签: angular subscription

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

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

3 个答案:

答案 0 :(得分:3)

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

您可以订阅所需的可观察对象,等待takeUntil运算符在另一个Observable发出时从Observable链退订:

您可以将新的Observable声明为主题:

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

此外,这是RxJ中的推荐模式,可破坏您的订阅!您可以了解有关takeUntil运算符here的更多信息。

答案 1 :(得分:2)

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

答案 2 :(得分:1)

您可以这样做:

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

}