如何使用 takeUntil RxJS 操作符来声明性地管理订阅

简介: 如何使用 takeUntil RxJS 操作符来声明性地管理订阅

本文介绍了在Angular中手动取消订阅的挑战以及如何通过使用takeUntil操作符实现声明式管理。这种方法有助于防止内存泄漏,并简化了复杂订阅的清理过程。

简介

Angular 处理取消订阅可观察对象的操作,比如从 HTTP 服务返回的可观察对象或者使用 async 管道时。然而,对于其他情况,管理所有订阅并确保取消长期存在的订阅可能会变得困难。而且,取消大部分订阅的策略也会带来自己的问题。

在本文中,您将看到一个依赖于手动订阅和取消订阅的 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 这样的操作符而不是手动取消订阅也将完成可观察对象,触发可观察对象上的任何完成事件。

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

结论

在本文中,您学习了如何使用 takeUntil 声明性地取消订阅。取消不必要的订阅有助于防止内存泄漏。声明性地取消订阅使您不需要对订阅保留引用。

还有其他类似的 RxJS 操作符 - 如 taketakeWhilefirst - 它们都会完成可观察对象。

如果您想了解更多关于 Angular 的知识,请查看我们的 Angular 主题页面,了解练习和编程项目。


目录
相关文章
讨论问题--数据类型、数组、传值/址API函数等
讨论问题--数据类型、数组、传值/址API函数等
67 0
|
前端开发 JavaScript
3 分钟温故知新 RxJS 【创建实例操作符】
RxJS 有很多神奇的东西,包括链式调用、惰性输出值、隔离数据和操作、响应式编程等等; 它是函数式编程中 monad 的一种实际应用;它是 promise 的进化形态;它是理解 JS 异步、处理异步的宝剑...... 所以,借着更文的契机,日日新、月月新,学习 RxJS 接着冲~
|
存储
rxjs Observable 自定义 Operator 的开发技巧
操作符是 RxJS 库和 Observables 的基础块。 它使我们能够通过使用一些关键字(函数)来执行复杂的操作。
98 0
rxjs Observable 自定义 Operator 的开发技巧
|
前端开发
前端项目实战8-hook中注意声明数据的顺序
前端项目实战8-hook中注意声明数据的顺序
60 0
前端项目实战8-hook中注意声明数据的顺序
rxjs Observable 两大类操作符简介
Observable 生产的数据,应该提供开发人员足够的自由度,对这些数据进行各种处理,比如 map / transform 等等。这就是 Rxjs Operator 大展身手的地方。
109 0
rxjs Observable 两大类操作符简介
rxjs 里 CombineLatest 操作符的一个使用场景
rxjs 里 CombineLatest 操作符的一个使用场景
78 0
rxjs 里 CombineLatest 操作符的一个使用场景
rxjs ThrottleTime 和 debounceTime 的操作符区别
rxjs ThrottleTime 和 debounceTime 的操作符区别
133 0
rxjs ThrottleTime 和 debounceTime 的操作符区别
|
存储 JavaScript 前端开发
Redux的基础用法详解(纯函数的概念)
和vue中的vuex一样,react也有进行状态管理的工具,最近自己在学习这一块的内容所以在此记录一下
207 0
|
缓存 前端开发 Swift
Swift实用小册06:函数的定义、参数、返回、调用
Swift实用小册06:函数的定义、参数、返回、调用
234 0
Swift实用小册06:函数的定义、参数、返回、调用
|
JavaScript 前端开发
「TypeScript」入门进阶(五)✈️---声明与声明合并
「TypeScript」入门进阶(五)✈️---声明与声明合并