【问题标题】:Angular RxJS Observable: takeUntil vs. unsubscribe with a Subscription [closed]Angular RxJS Observable:takeUntil 与使用订阅取消订阅 [关闭]
【发布时间】:2020-02-14 03:34:02
【问题描述】:

有几种方法可以取消订阅 Angular 组件上的 observables(使用 ngOnDestroy)。应该首选以下哪个选项以及为什么(例如技术原因、性能等)?

选项 1:采取Until

使用 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:?

【问题讨论】:

  • 你可以问十个人,他们都有自己的喜好。您提到的所有选项都是完全有效的,并且没有明确的“最佳”选项。 IMO takeUntil 是最好的解决方案。
  • 好的,我想知道一个或另一个选项是否有技术原因...感谢您的评论
  • @HoraceP.Greeley 我知道已经晚了,但为什么需要 this.destroy$.next();在选项 1 上?
  • @raberana next() 是必需的,因为“takeUntil”通过调用 destory$.next() 直到 destroy$ 具有值。另一个主题,但很重要:takeUntil 应该在管道中的最后一个位置。见cartant.medium.com/rxjs-avoiding-takeuntil-leaks-fb5182d047ef

标签: angular rxjs observable unsubscribe


【解决方案1】:
  • 选项 1:简洁明了。像魅力一样工作
  • 选项 2:更程序化,更少流式。奇迹般有效。请注意,您的直播不会收到可能导致意外行为的“完成”事件
  • 选项 3:takeWhile - 将保留订阅,直到创建发射,然后评估 takeWhile。这可能导致意外行为。尽管如此,最终还是有效的

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

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

他的意见:

您可能应该使用像 takeUntil 这样的运算符来管理您的 RxJS 订阅。根据经验,如果您看到在一个组件中管理两个或多个订阅,您应该想知道是否可以更好地组合这些订阅。

【讨论】:

  • 在使用takeUntil时,我们应该在ngOnDestroy()中使用this.destroy$.next()this.destroy$.complete()吗?
  • takeUntil 需要发射,所以你必须next() 一些东西(即使undefined)complete() 是多余的,因为没有人在听那个事件。
  • 是不是说我们在使用takeUntil的时候在ngOnDestroy()中不需要this.destroy$.next()和this.destroy$.complete()?
【解决方案2】:

就个人而言,我也选择了选项1,即使用takeUntil

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

例如,如果我们不将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 写了一篇非常好的 article,介绍了取消订阅 observables 的不同方式(包括 unsubscribe()takeUntil() 运算符)。我也建议你看看它。

【讨论】:

  • 在使用takeUntil时,我们应该在ngOnDestroy()中使用this.destroy$.next()this.destroy$.complete()吗?
  • @Fredrick 是的,我们应该!抱歉,我的回答没有反映出来。
  • 那么我认为使用unsubscribe 似乎比takeUntil 更好。因为它显示为 showter 版本,但几乎相似,我们也称之为方法onDestroy。不是吗?
  • @Fredrick 是的,但是如果您的组件中有多个订阅,使用takeUntil 方法会更干净。相信这篇文章给出了完整的解释medium.com/@benlesh/rxjs-dont-unsubscribe-6753ed4fda87
  • 谢谢,但我也阅读了this 文章,发现两种方法在代码长度方面几乎没有区别(其中一种是内部块,另一种是外部块)。
【解决方案3】:

对于您的示例,我不会选择 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>

【讨论】:

  • 他的示例旨在为问题提供上下文,而您的答案在实际情况下是正确的,但对具体问题并没有真正的帮助。
猜你喜欢
  • 2021-11-18
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 2021-03-03
  • 1970-01-01
  • 2017-03-26
  • 2020-10-28
相关资源
最近更新 更多