我需要取消订阅 Angular Observable 吗?

Do I need to unsubscribe from an Angular Observable?

关于 如果和何时 你应该取消订阅 Angular Observable 的问题,很难得到一个直接的答案。

我有以下场景:

this.subscription = this.service.makeHTTPCall(stuff).subscribe(x => {
//do something
});

我看到了一些解决方案:

  1. 不要将订阅存储为变量,这是否意味着我不必取消订阅?

    this.service.makeHTTPCall(stuff).subscribe(x => {
    //do something
    });
    
  2. 将订阅存储为变量并在 ngOnDestroy 中取消订阅

    ngOnDestroy() {
    if (this.subscription) { this.subscription.unsubscribe(); }
    }
    
  3. 什么都不做,Angular 为您整理所有退订内容

我知道有像 ng-take-until-destroy 这样的第三方库,但假设我们没有任何第三方库,这是取消订阅的建议方法?

您无需手动取消订阅 HTTP Observable 和 Router observable。除了这两个之外,您创建的任何主题或可观察对象都使用您已经提到的一种方式手动取消订阅,另一种方式可以使用 async 运算符。异步运算符会自动为您取消订阅,这也是您可以使用的另一种方式takeUntil 运算符

来自

TLDR:

For this question there are (2) kinds of Observables - finite value and infinite value.

http Observables produce finite (1) values and something like a DOM event listener Observables produce infinite values.

If you manually call subscribe (not using async pipe), then unsubscribe from infinite Observables.

Don't worry about finite ones, RxJs will take care of them.

您无需手动取消订阅 HTTP Observable 和 Router observable。对于所有其他订阅者,最佳做法是创建一个主题 destroy$,然后使用 rxjs 管道 takeUntil() 获取所有订阅者,直到 destroy$ 处于活动状态。在 ngOnDestroy 中,你在 destroy$ 主题中发出 true 并取消订阅它。所有其他订阅者将一起停止。 Angular 不要为你整理所有退订的东西,你应该自己做。它可以提供给许多难以调试的错误,以便在组件销毁后离开 gost 订阅者。下面是示例代码:

onDestroy$: Subject<boolean> = new Subject();

ngOnInit() {
 this.service.someSubscriber.pipe(takeUntil(this.destroy$)).subscribe(() => 
{ //do stuff 
})
this.service.someSubscriber2.pipe(takeUntil(this.destroy$)).subscribe(() => 
{ //do stuff 
})
this.service.someSubscriber3.pipe(takeUntil(this.destroy$)).subscribe(() => 
{ //do stuff 
})
}

ngOnDestroy() {
  this.destroy$.next(true);
  this.destroy$.unsubscribe();
}

在 html 模板中,异步管道会自动触发取消订阅,因此当您使用它时,您不必担心它。

对于一些冷的可观察对象,您不需要手动取消订阅,因为它们会发出一次,然后立即完成。 http 服务就是此类可观察对象的一个​​示例。

话虽如此,如果如果您不知道一个 Observable 是否会发出一次并立即完成,那么您应该始终进行适当的清理。

就我个人而言,我更喜欢使用 take(1) 运算符,它会接受第一个响应,然后自行取消订阅:

someObs.pipe(take(1)).subscribe(...)