Angular - DialogRef - Unsubscribe - 我需要在 afterClosed 中取消订阅吗?

57

我的同事问我是否需要取消订阅对话框的afterClosed() Observable。

我们在ngOnDestroy()中使用takeUntil模式来取消订阅所有Observables。

this.backEvent = fromEvent(window, 'popstate')
    .pipe(
        takeUntil(this.destroy$)
    )
    .subscribe(
        () => {
            this.navigationService.backClicked = true;
            this.navigationService.navigateBackToDirectoryCenter();
        }
    );

ngOnDestroy()

:在Angular组件被销毁时调用的生命周期钩子函数。

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

那么,从 afterClosed() Observable 中取消订阅是必要的吗?

dialogRef.afterClosed().subscribe(
    (data) => {
            console.log(data);
        }
    },
);
或者?
dialogRef.afterClosed()
    .pipe(
        takeUntil(this.destroy$)
    )
    .subscribe(
        (data) => {
            console.log(data);
        },
    );

2
我从未在对话框关闭后取消订阅,也没有出现任何问题(至少目前还没有)。但是这是一个好问题。 - Orestis Zekai
3
不,您不需要取消订阅,因为它会自动完成。 - Archit Garg
4个回答

114

不需要

您无需取消订阅,因为可观察对象本身会完成。您可以通过添加finalize块来验证是否可观察对象自行完成。

import { finalize } from "rxjs/operators";
dialogRef
  .afterClosed()
  .pipe(finalize(() => console.log("completed")))
  .subscribe(data => {
    console.log(data);
  });

当您关闭对话框时,控制台将显示completed,这表示您不需要取消订阅该可观察对象。


2
如果您使用 switchMap 链接一些可观测对象,它是否以相同的方式工作? - wisnix
switchMap 会丢弃 afterClose() 中的 observable,并使用 switchMap 回调中的 observable,需要确保其能够正确地完成。 - mr.vea

9

通常,您会取消订阅可观察对象以防止内存泄漏和避免出现错误,特别是当订阅块使用this.xxxx组件属性时。

即使订阅完成并且您不需要考虑内存泄漏,但您仍应该了解第二个问题。

调用dialogRef.afterClosed()的宿主组件可能会在对话框仍然可见时被销毁。订阅将在关闭后才发出信号,在订阅块中访问组件属性时,它将抛出一个错误。

我认为这是一个罕见的情况,即宿主组件在对话框处于活动状态时被销毁,但我想指出这种边缘情况。例如,浮动按钮打开一个对话框,但在滚动或其他情况下消失。


5

3
我认为文档没有详细说明,而且取消订阅可能只是文档范围之外的内容。因此,我不会依赖于“如果文档中没有提到,则不需要”的说法。 - ulmas

1

您可以通过在订阅调用中设置完成回调来自行测试。我很久以前就进行了测试,以确认其他人所说的内容; 不需要担心取消订阅。无论如何,测试这一点都是一个好的做法。

observable.subscribe(
    (value) => { ... },
    (error) => { ... },
    () => { console.log('complete!'); }
);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接