Angular RxJS Observable:takeUntil 与使用订阅取消订阅

Angular RxJS Observable: takeUntil vs. unsubscribe with a Subscription

有几种方法可以取消订阅 Angular 组件上的可观察对象(通过使用 ngOnDestroy)。应首选以下哪个选项以及原因(例如技术原因、性能等)?

选项 1:takeUntil

使用 RxJS takeUntil 取消订阅

@Component({
  selector: "app-flights",
  templateUrl: "./flights.component.html"
})
export class FlightsComponent implements OnDestroy, OnInit {
  private readonly destroy$ = new Subject();

  public flights: FlightModel[];

  constructor(private readonly flightService: FlightService) {}

  ngOnInit() {
    this.flightService
      .getAll()
      .pipe(takeUntil(this.destroy$))
      .subscribe(flights => (this.flights = flights));
  }

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

选项 2:.unsubscribe()

显式调用 .unsubscribe(),例如通过使用单独的订阅实例

@Component({
  selector: "app-flights",
  templateUrl: "./flights.component.html"
})
export class FlightsComponent implements OnDestroy, OnInit {
  private readonly subscriptions = new Subscription();

  public flights: FlightModel[];

  constructor(private readonly flightService: FlightService) {}

  ngOnInit() {
    const subscription = this.flightService
      .getAll()
      .subscribe(flights => (this.flights = flights));

    this.subscriptions.add(subscription);
  }

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

选项 3:takeWhile

使用 RxJS takeWhile 退订

选项 n:?

  • 选项 1:简洁明了。很有魅力
  • 选项 2:更程序化,更少流式。奇迹般有效。请注意,您的流不会收到可能导致意外行为的 'complete' 事件
  • 选项 3:takeWhile - 将保留订阅直到创建发射,然后评估 takeWhile。这可能会导致意外行为。尽管如此,最终还是有效

TLDR;这里没有错。选择您认为适合您的需求并传达您的意图的内容。

Ben Lesh 也写了一篇很好的文章 post 关于不同的退订方式 https://medium.com/@benlesh/rxjs-dont-unsubscribe-6753ed4fda87

他的意见:

You should probably be using operators like takeUntil to manage your RxJS subscriptions. As a rule of thumb, if you see two or more subscriptions being managed in a single component, you should wonder if you could be composing those better.

我个人也是选择方案1,即使用takeUntil

但是,将 takeUntil() 运算符放在管道序列的最后一个 RxJS 运算符上很重要,如 here 所述。

例如,如果我们不将 takeUntil() 作为最后一个运算符,订阅者将继续订阅后续的 switchMap() 运算符:

this.flightService.getAll()
  .pipe(
    takeUntil(this.destroy$),
    switchMap(() => this.doSomethingElse()),
  ).subscribe(flights => (this.flights = flights));

因此,正确的做法是:

this.flightService.getAll()
  .pipe(
    switchMap(() => this.doSomethingElse()),
    takeUntil(this.destroy$),
  ).subscribe(flights => (this.flights = flights));

Brian Love 在取消订阅可观察对象的不同方式(包括 unsubscribe()takeUntil() 运算符)上写了一篇非常好的 article。我也推荐你看看。

对于您的示例,我不会选择这 3 个选项中的任何一个。当您只想分配一个值时,然后存储 Observable 并使用异步管道订阅它。

@Component({
  selector: "app-flights",
  templateUrl: "./flights.component.html"
})
export class FlightsComponent implements OnDestroy, OnInit {  
  public flights$: Observable<FlightModel[]>;

  constructor(private readonly flightService: FlightService) {}

  ngOnInit() {
    this.flights$ = this.flightService.getAll();
  }
}

<ng-container *ngIf="flights$ | async as flights">
  <ng-container *ngFor="let flight of flights">
    {{ flight | json }}
  </ng-container>
</ng-container>