订阅的自定义完整方法是否自行取消订阅?

Does a custom complete method of a subscription unsubscribe on its own?

我创建了一个 Observable:

public getData(): Observable<any> {
    return this.getEndpoint()
      .pipe(
        switchMap((endpoint) =>
          this.http.get<any>(endpoint)
        ),
        take(1)
      );
  }

我订阅了可观察对象并执行了 HTTP 调用

this.getData().subscribe({
      next: data => this.data = data,
      complete: () => {
        this.someActions();
      },
    });

由于 Observable 管道中的 take(1),Observable 在发出一个值后完成。所以在我们执行 someActions() 的地方调用了完整的方法。 由于此方法是自定义的,订阅是自行取消订阅,还是必须在完整方法中手动取消订阅?

编辑: 订阅的完整方法如何取消订阅?

您永远不需要取消订阅已完成的可观察对象。 Observables 通过对其观察者的 complete() 或 error() 调用完成。这是 observable 合约的一部分。

考虑以下示例。

const sub = interval(250).pipe(
  take(4),
  map(x => x + 1)
).subscribe({
  next: console.log,
  complete: () => console.log("This observable completed naturally"),
  err: _ => console.log("This observable completed with an error")
});

console.log("Sub is closed, no need to unsubscribe? " + sub.closed);

setTimeout(() => {
    console.log("Sub is closed, no need to unsubscribe? " + sub.closed);
}, 1250);

控制台输出:

Sub is closed, no need to unsubscribe? false
1
2
3
4
This observable completed naturally
Sub is closed, no need to unsubscribe? true

这表明将完成的可观察对象不需要取消订阅,也不会造成内存泄漏。问题在于 long-lived 的可观察对象(比如没有 taketakeWhiletakeWhen 等运算符的区间)。

例如,在 angular 中,只要组件存在,一些可观察对象就需要存在,但不再存在。它们链接到组件 life-cycle。问题是忘记取消订阅像这样的 observables(那些 complete 自己)会导致内存泄漏。


同步示例:

of("Hello There").subscribe({
  next: console.log,
  complete: () => console.log("This observable completed naturally"),
  err: _ => console.log("This observable completed with an error")
});

您无需取消订阅此可观察对象。事实上,因为它 运行 是同步的,所以它会在您取消订阅之前关闭。

 const sub = of(1).subscribe();
 console.log(sub.closed); // output: true

退订所需示例:

const sub = interval(1000).subscribe(console.log);
setTimeout(() => {
    console.log("Sub is closed: " + sub.closed);
    sub.unsubscribe();
    console.log("Sub is closed: " + sub.closed);
}, 60 x 60 x 1000);

这里我们启动一个 observable,然后我们等待 一个小时 看看它是否关闭。然后我们取消订阅并检查它是否已关闭。这个间隔 运行 永远 直到明确取消订阅。

控制台输出:

0
1
2
... [skipping ahead]
3596
3597
3598
3599
Sub is closed: false
Sub is closed: true