如何使用takeUntilRxJS运算符以声明方式管理订阅

来自菜鸟教程
跳转至:导航、​搜索

介绍

Angular 处理可观察订阅的取消订阅,例如从 HTTP 服务返回的订阅,或者在使用 异步管道 时。 但是,对于其他情况,管理所有订阅并确保取消订阅长期存在的订阅可能很快变得困难。 取消订阅大多数订阅的政策也会有其自身的问题。

在本文中,您将看到一个依赖手动订阅和取消订阅的示例 Angular 应用程序。 然后,将其与使用 takeUntil 运算符以声明方式管理订阅的示例 Angular 应用程序进行比较。

先决条件

如果您想继续阅读本文,您将需要:

  • 熟悉 RxJS 库,特别是 ObservableSubscription 会很有帮助。
  • 熟悉 Apollo 和 GraphQL 会有所帮助,但不是必需的。

本教程已使用 Node v15.3.0、npm v6.14.9、@angular/core v11.0.4、rxjs v6.6.3、apollo-angular v2.1.0 验证, graph-tag v2.11.0。 本文经过编辑以反映从 @angular/corerxjs 早期版本迁移的变化。

手动退订

让我们从一个示例开始,您将手动取消订阅两个订阅。

在此示例中,代码订阅 Apollo watchQuery 以从 GraphQL 端点获取数据。

当调用 onStartInterval 方法时,该代码还创建了一个可观察的间隔,您可以订阅该间隔。

import { Component, OnInit, OnDestroy } from '@angular/core';

import { Subscription, interval } from 'rxjs';

import { Apollo } from 'apollo-angular';
import gql from 'graphql-tag';

@Component({ ... })
export class AppComponent implements OnInit, OnDestroy {
  myQuerySubscription: Subscription;
  myIntervalSubscription: Subscription;

  constructor(private apollo: Apollo) {}

  ngOnInit() {
    this.myQuerySubscription = this.apollo.watchQuery<any>({
      query: gql`
        query getAllPosts {
          allPosts {
            title
            description
            publishedAt
          }
        }
      `
    })
    .valueChanges
    .subscribe(({data}) => {
      console.log(data);
    });
  }

  onStartInterval() {
    this.myIntervalSubscription = interval(250).subscribe(value => {
      console.log('Current value:', value);
    });
  }

  ngOnDestroy() {
    this.myQuerySubscription.unsubscribe();

    if (this.myIntervalSubscription) {
      this.myIntervalSubscription.unsubscribe();
    }
  }
}

现在想象一下,你的组件有很多类似的订阅,它可以很快变成一个相当大的过程,以确保在组件被销毁时所有的东西都被取消订阅。

使用 takeUntil 以声明方式取消订阅

解决方案是使用 takeUntil 运算符组合订阅,并使用在 ngOnDestroy 生命周期挂钩 中发出真值的主题。

下面的代码片段做了完全相同的事情,但这次代码将以声明方式取消订阅。 您会注意到一个额外的好处是您不再需要保留对我们订阅的引用。

import { Component, OnInit, OnDestroy } from '@angular/core';

import { Subject, interval } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

import { Apollo } from 'apollo-angular';
import gql from 'graphql-tag';

@Component({ ... })
export class AppComponent implements OnInit, OnDestroy {
  destroy$: Subject<boolean> = new Subject<boolean>();

  constructor(private apollo: Apollo) {}

  ngOnInit() {
    this.apollo.watchQuery<any>({
      query: gql`
        query getAllPosts {
          allPosts {
            title
            description
            publishedAt
          }
        }
      `
    })
    .valueChanges
    .pipe(takeUntil(this.destroy$))
    .subscribe(({data}) => {
      console.log(data);
    });
  }

  onStartInterval() {
    interval(250)
    .pipe(takeUntil(this.destroy$))
    .subscribe(value => {
      console.log('Current value:', value);
    });
  }

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

请注意如何使用像 takeUntil 这样的运算符而不是手动取消订阅也将完成 observable,触发 observable 上的任何完成事件。

请务必检查您的代码以确保这不会产生任何意外的副作用。

结论

在本文中,您了解了如何使用 takeUntil 以声明方式取消订阅。 取消订阅不必要的订阅有助于防止内存泄漏。 声明式取消订阅允许您不需要对订阅的引用。

还有其他类似的 RxJS 运算符——如 taketakeWhilefirst——它们都将完成 observable。

如果您想了解有关 Angular 的更多信息,请查看 我们的 Angular 主题页面 以获取练习和编程项目。