Angular 2 - 订阅FormControl的valueChanges是否需要取消订阅?

use*_*183 12 rxjs angular

以下是我所询问的一个简单示例:

class AppComponent {

  someInput: FormControl = new FormControl('');
  private subscription: Subscription;

  constructor(){

    this.subscription = this.someInput.valueChanges
        .subscribe(() => console.log("testing"));
  }
}
Run Code Online (Sandbox Code Playgroud)

我有两个问题:

1)我是否必须最终取消订阅?2)最重要的是,无论答案是什么,#1,答案是什么?

任何见解将不胜感激!

谢谢!

rmc*_*rry 22

  1. 是的你是.请注意,您不需要取消订阅http调用,因为它们会自动完成.

  2. 您必须取消订阅以防止内存泄漏并避免应用程序中出现意外的副作用.

例如,当组件被销毁时,如果您不取消订阅,则订阅将保留.下次用户导航回该页面并再次加载组件时,它将创建另一个订阅valueChanges- 现在您有2个活动订阅同时处理数据,这将导致您的应用程序出现意外行为.

有一种相对简单的方法来设置自动取消订阅.

RxJS的方式是使用takeUntil - 它基本上允许你设置一个用户继续监听直到你告诉它不要 :)

首先,我们需要在组件中使用destroy主题:

  private destroy$ = new Subject();
Run Code Online (Sandbox Code Playgroud)

然后告诉它在我们的组件被销毁时发出一个值:

  ngOnDestroy(){
    this.destroy$.next();
  }
Run Code Online (Sandbox Code Playgroud)

现在设置您的订阅使用它:

this.someInput.valueChanges
  .debounceTime(1000)
  .distinctUntilChanged()
  .takeUntil(this.destroy$)
  .subscribe (newValue => {
Run Code Online (Sandbox Code Playgroud)

所有这样的订阅设置将在收到销毁通知时自动取消订阅.

例如,如果你有一个动态添加控件的ngFor,并且添加的每个控件都有一个valueChanges订阅(例如一个控件数组),这将特别有用.在这种情况下,您不需要在ngOnDestroy中循环遍历数组并逐个取消订阅.只需使用takeUntil :)

我建议阅读Ben Lesh的文章(谷歌的RxJS首席工程师),了解takeUntil的一个很好的概述,包括优点/缺点.

  • 只是想知道,当组件被销毁并且有资格进行 gc 时,没有其他任何东西引用“someInput”对象及其“valueChanges”可观察实例和订阅函数,因此它们也应该有资格进行 gc。那么为什么会出现内存泄漏呢?rxjs 是否在“Observable”实例之外的某种状态下保留对订阅函数的引用?这对我来说听起来不太可能,但我不熟悉 rxjs 的内部工作原理。我在使用“interval”或类似内容时看到了问题,但在这种情况下没有。 (8认同)

jen*_*ent 5

我强烈推荐 rxjs 扩展https://github.com/ngneat/until-destroy。它将帮助您编写更少的代码。

@UntilDestroy()
@Component({})
export class InboxComponent {
  ngOnInit() {
    this.someInput.valueChanges
      .pipe(untilDestroyed(this))
      .subscribe();
  }
}

Run Code Online (Sandbox Code Playgroud)