Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >[译]Rxjs&Angular-退订可观察对象的n种方式

[译]Rxjs&Angular-退订可观察对象的n种方式

作者头像
laggage
修改于 2021-02-07 02:35:06
修改于 2021-02-07 02:35:06
1.2K0
举报
文章被收录于专栏:laggage-weblaggage-web

原文/出处: RxJS & Angular — Unsubscribe Like a Pro

在angular项目中我们不可避免的要使用RxJS可观察对象(Observables)来进行订阅(Subscribe)和退订(Unsubscribe)操作;

概述

我们的每个angular项目中都会用到RxJS, RxJS在我们的angular app中对数据流和性能有非常大的影响。

为了避免内存泄漏,在适当的时机对可观察对象进行退订是非常重要的; 本文会向你展示各种在angular组件中退订可观察对象的方法!

首先,我们创建一个帮助类来帮我们创建的订阅对象(Subscription)

代码语言:txt
AI代码解释
复制
@Injectable({
  providedIn: 'root',
})
export class DummyService {
  getEmissions(scope: string): Observable<string> {
    return Observable.create((observer) => {
      console.log(`${scope} Subscribed`);

      const subscription: Subscription = timer(0, 1000)
        .pipe(
          map((n) => `${scope} Emission #${n}`),
          tap(console.log)
        )
        .subscribe(observer);

      return () => {
        subscription.unsubscribe();
        console.log(`${scope} Unsubscribed`);
      };
    });
  }
}

我们的帮助类有一个getEmissions方法, 它接受一个scope参数来记录日志, 它的返回值是一个会每秒发出 ${scope} Emission #n字符串的可观察对象.

方式一 "常规"的取消订阅的方式

最简单的订阅和取消订阅一个可观察对象的方式是在 ngOnInit 方法中订阅可观察对象(Observable), 然后在组件类中创建一个类属性用来保存这个订阅(Subscription), 并在 ngOnDestroy 中取消对可观察对象对订阅. 简单起见, 我们可以使用Subscription.EMPTY来初始化一个订阅对象(Subscription), 这样可以防止在取消订阅时遇到空引用对问题.

代码语言:txt
AI代码解释
复制
@Component({
  selector: 'app-regular',
  template: `<div>{{ emission }}</div>`,
})
export class RegularComponent implements OnInit, OnDestroy {
  emission: string;

  /* 
    Note: we initialize to Subscription.EMPTY to avoid null checking within ngOnDestroy
   */
  private subscription: Subscription = Subscription.EMPTY;

  constructor(private dummyService: DummyService) {}

  ngOnInit(): void {
    this.subscription = this.dummyService
      .getEmissions('Regular')
      .subscribe((emission) => (this.emission = emission));
  }

  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }
}

为了验证代码有效我们在三秒后从DOM中移除这个组件

如上所述, 这是最基本对取消订阅的方式, 如果我们的组件类中只有一个订阅对象(Subscription), 这种方式没什么问题. 但是当我们有多个订阅对象(Subscription)时, 针对每一个我们都需要在组件类中创建一个字段保存这个对象的的引用并在 ngOnDestroy 中调用 unsubscribe来取消订阅.

方式二 使用 Subscription.add 方法

RxJS的订阅类(Subscription)内建了 Subscription.add 方法允许我们使用单个订阅对象的实例(Subscription instance)来简化我们操作多个订阅对象的.

首先, 在组件类中使用new Subscription()实例化创建一个字段, 然后调用该实例的 Subscription.add 方法, 最后在 ngOnDestroy 中取消订阅.

代码语言:txt
AI代码解释
复制
@Component({
  selector: 'app-add',
  template: `
    <div>{{ emissionA }}</div>
    <div>{{ emissionB }}</div>
  `,
})
export class AddComponent implements OnInit, OnDestroy {
  emissionA: string;
  emissionB: string;

  private subscription: Subscription = new Subscription();

  constructor(private dummyService: DummyService) {}

  ngOnInit(): void {
    this.subscription.add(
      this.dummyService
        .getEmissions('[Add A]')
        .subscribe((emission) => (this.emissionA = emission))
    );

    this.subscription.add(
      this.dummyService
        .getEmissions('[Add B]')
        .subscribe((emission) => (this.emissionB = emission))
    );
  }

  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }
}

打开浏览器控制台, 我们可以看到两个订阅对象:

使用这种方式, 我们可以使用RsJS内建的方法轻松的取消订阅多个可观察对象而不必在组件类创建多个字段保存订阅对象的引用.

方式三 AsyncPipe

Angular内置了许多非常有用的管道(pipe), 其中一个就是AsyncPipe. AsyncPipe接受一个可观察对象并在组件生命周期结束时(ngOnDestroy)自动取消订阅.

与前两个示例不同, 这里我们不需要在组件中手动取消订阅, 而是将可观察对象(Observable)传递个 AsyncPipe:

代码语言:txt
AI代码解释
复制
@Component({
  selector: 'app-async',
  template: `<div>{{ emissions$ | async }}</div>`
})
export class AsyncComponent implements OnInit {
  emissions$: Observable<string>;

  constructor(private dummyService: DummyService) {}

  ngOnInit(): void {
    this.emissions$ = this.dummyService.getEmissions('[Async]');
  }
}

在我看来, 这是在Angular中使用可观察对象(Observables)最简明的方式. 你只需创建可观察对象(Observables)然后Angular会帮助你进行订阅和取消订阅.

方式4 takeUntil 操作符

RxJS包含许多有用的操作符, takeUntil就是其中之一. 像这个操作符的签名一样, takeUntil 接受一个会发出取消订阅源可观察对象通知的可观察对象(notifier).

在我们的示例中, 我们希望在组件被销毁后发出通知, 所以我们给组件类添加一个叫 componentDestroyed$ 的字段, 它的类型是 Subject<void>, 这个字段承担了通知人(notifier)的角色.

然后我们只需在ngOnDestroy发出"通知"即可, 最终的代码像下面这样:

代码语言:txt
AI代码解释
复制
@Component({
  selector: 'app-until',
  template: `<div>{{ emission }}</div>`,
})
export class UntilComponent implements OnInit, OnDestroy {
  emission: string;

  private componentDestroyed$: Subject<void> = new Subject<void>();

  constructor(private dummyService: DummyService) {}

  ngOnInit(): void {
    this.dummyService
      .getEmissions('takeUntil')
      .pipe(takeUntil(this.componentDestroyed$))
      .subscribe((emission) => (this.emission = emission));
  }

  ngOnDestroy(): void {
    this.componentDestroyed$.next();
  }
}

与之前常规的方式相比, 这种方式在我们有多个订阅对象时不必在组件类中创建多个字段保存对订阅对象的引用. 我们只需在管道中加入 takeUntil(componentDestroyed$) 即可, 剩下的RxJS会帮我们完成.

方式五 SubSink 库

SubSinkWard Bell写的一个很棒的库, 它使你可以优雅的在你的组件中取消对可观察对象的订阅.

首先, 通过npm i subsinkyarn add subsink安装SubSink. 然后在组件类中创建一个SubSink类型的字段.

SubSink有两种方式, 一种是简单技术(使用sink属性设置器), 另一种是 数组/添加(Array/Add)技术.

使用简单技术只需要使用sink设置器属性即可. 使用数组/添加(Array/Add)技术的话代码类似RxJS原生的Subscription.add

为每一种方式创建一个订阅对象, 我们的组件类看起来像下面这样

代码语言:txt
AI代码解释
复制
@Component({
  selector: 'app-sink',
  template: `
    <div>{{ easyEmission }}</div>
    <div>{{ arrayAddEmission }}</div>
  `,
})
export class SinkComponent implements OnInit, OnDestroy {
  easyEmission: string;
  arrayAddEmission: string;

  private subs = new SubSink();

  constructor(private dummyService: DummyService) {}

  ngOnInit(): void {
    /* 使用简单技术 */
    this.subs.sink = this.dummyService
      .getEmissions('[Easy Technique]')
      .subscribe((emission) => (this.easyEmission = emission));

    /* 使用数组/添加(Array/Add)技术 */
    this.subs.add(
      this.dummyService
        .getEmissions('[Array/Add Technique]')
        .subscribe((emission) => (this.easyEmission = emission))
    );
  }

  ngOnDestroy(): void {
    this.subs.unsubscribe();
  }
}

方式六 until-destroy 库

注意: 这个库在Pre Ivy Angular上行为不同, 更多信息请访问文档

until-destroyngneat许多很棒的库之一, 它使用UntilDestroy装饰器来确认哪些字段的是订阅对象(Subscriptions)并在组件销毁时取消订阅它们;

我们还可以不通过组件类字段, 而是使用until-destroy定义的叫untilDestroyed的RxJS操作符来取消订阅.

要使用它我们需要给组件类加上 UntilDestroy 装饰器, 然后在可观察对象管道中加入 untilDestroyed 操作符:

代码语言:txt
AI代码解释
复制
@UntilDestroy()
@Component({
  selector: 'app-destroyed',
  template: `<div>{{ emission }}</div> `,
})
export class DestroyedComponent implements OnInit {
  emission: string;

  constructor(private dummyService: DummyService) {}

  ngOnInit(): void {
    this.dummyService
      .getEmissions('[UntilDestroy]')
      .pipe(untilDestroyed(this))
      .subscribe((emission) => (this.emission = emission));
  }
}

总的来说, until-destroy是个非常强大的库, 他可以帮你自动取消对可观察对象的订阅.

此外, until-destroy还有许多其他在本文中没有进行说明的特性, 所以赶快去看看它们的github仓库吧!

总结

上面我们已经看到来许多订阅和退订可观察对象方式, 每个都各有各的优劣并且有着不同的编码风格.

但是最重要是不管我们选择那种方式, 我们都要保持编码风格的一致

> 博客园: https://www.cnblogs.com/laggage/p/14380301.html

本文系外文翻译,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系外文翻译,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
augular 英雄之旅
组件是 Angular 应用中的基本构造块。 它们在屏幕上显示数据,监听用户输入,并且根据这些输入执行相应的动作。 像一组html的集合,可与用户交互,可复用, 创建好的项目的src目录下有个app目录,这是整个程序的根组件 app.component.ts— 组件的类代码,这是用 TypeScript 写的。
刘嘿哈
2022/10/25
1.7K0
Angular 实践:如何优雅地发起和处理请求
Tips: 本文实现重度依赖 ObservableInput,灵感来自同事 @Mengqi Zhang 实现的 asyncData 指令,但之前没有 ObservableInput 的装饰器,处理响应 Input 变更相对麻烦一些,所以这里使用 ObservableInput 重新实现。
灵雀云
2020/02/26
8680
Angular 实践:如何优雅地发起和处理请求
RxJS教程
拉取? 由消费者来决定何时从生产者那接收数据,生产者本身不知道数据何时交付到消费者手中的。
全栈程序员站长
2022/06/29
1.8K0
RxJS 入门到搬砖 之 Subscription 和 Subject
什么是 Subscription? Subscription 是一个表示一次性资源的对象,通常是 Observable 的执行。Subscription 有一个重要的方法 unsubscribe,不接受任何参数,只是释放 Subcription 持有的资源。在之前的 RxJS 中,Subscription 被称为 Disposable。
Cellinlab
2023/05/17
9360
80 行代码实现简易 RxJS
RxJS 是一个响应式的库,它接收从事件源发出的一个个事件,经过处理管道的层层处理之后,传入最终的接收者,这个处理管道是由操作符组成的,开发者只需要选择和组合操作符就能完成各种异步逻辑,极大简化了异步编程。除此以外,RxJS 的设计还遵循了函数式、流的理念。
神说要有光zxg
2022/03/03
1.3K0
80 行代码实现简易 RxJS
Angular 组件通信
上一篇,我们讲了 Angular 结合 NG-ZORRO 快速开发。前端开发,很大程度上是组件化开发,永远离不开组件之间的通信。那么,在 Angular 开发中,其组件之间的通信是怎么样的呢?
Jimmy_is_jimmy
2022/04/15
2K0
Angular快速学习笔记(4) -- Observable与RxJS
介绍RxJS前,先介绍Observable 可观察对象(Observable) 可观察对象支持在应用中的发布者和订阅者之间传递消息。 可观察对象可以发送多个任意类型的值 —— 字面量、消息、事件。 基本用法和词汇 作为发布者,你创建一个 Observable 的实例,其中定义了一个订阅者(subscriber)函数。 当有消费者调用 subscribe() 方法时,这个函数就会执行。 订阅者函数用于定义“如何获取或生成那些要发布的值或消息”。 要执行所创建的可观察对象,并开始从中接收通知,你就要调用它的 s
JadePeng
2018/05/28
5.3K0
Angular进阶教程2-<依赖注入+RxJS>
组件\color{#0abb3c}{组件}组件不应该直接获取或保存数据,它们应该聚焦于展示数据,而把数据访问和处理的职责委托给某个服务\color{#0abb3c}{服务}服务。那面对组件和服务之间的关系,该如何处理他们之间的依赖关系呢?Angular就引入了依赖注入框架\color{#0abb3c}{依赖注入框架}依赖注入框架去解决这件事情。
玖柒的小窝
2021/12/08
4.2K0
Angular进阶教程2-<依赖注入+RxJS>
angular面试题及答案_angular面试
ngAfterContentInit:当把内容投影进组件之后调用,第一次调用ngDocheck()之后调用,只调用一次,只适用于组件
全栈程序员站长
2022/11/02
11.3K0
Angular 自定义服务 notification
我们在 app/services 中添加 notification.service.ts 服务文件(请使用命令行生成),添加相关的内容:
Jimmy_is_jimmy
2022/04/15
5100
Angular 自定义服务 notification
Rxjs源码解析(一)Observable
通过 new Observable() 方法创建了一个可观察对象 observable,然后通过 subscribe 方法订阅这个observable,订阅的时候会执行在 new Observable时候传入的函数参数,那么就来看下 new Observable到底做了什么
阿珍
2022/07/01
1.7K0
用VSCode开发一个asp.net core2.0+angular5项目(5): Angular5+asp.net core 2.0 web api文件上传
这部分就讲从angular5的客户端上传图片到asp.net core 2.0的 web api. 这是需要的源码: https://pan.baidu.com/s/1Eqc4MRiQDwOHmu0O
solenovex
2018/03/29
2.9K0
用VSCode开发一个asp.net core2.0+angular5项目(5): Angular5+asp.net core 2.0 web api文件上传
Rxjs 中怎么处理和抓取错误
使用 Rxjs,对于初学者来说,当我们处理 observables 错误的时候容易疑惑,因为我们会考虑使用 try-catch 方式捕获。但是,Rxjs 是通过操作符来管理错误。
Jimmy_is_jimmy
2022/09/26
2.1K0
RxJs简介
这两年,各种异步编程框架,上面RxJava,RxAndroid,RxSwift等等,今天要聊的是RxJs,对于我等入门不久的前端工程师来说,这个框架还是比较有新颖的,中文官网地址:http://cn.rx.js.org/
xiangzhihong
2022/11/30
3.7K0
详解ANGULAR2组件中的变化检测机制(对比ANGULAR1的脏检测)
组件和变化检测器 如你所知,Angular 2 应用程序是一颗组件树,而每个组件都有自己的变化检测器,这意味着应用程序也是一颗变化检测器树。顺便说一句,你可能会想。是由谁来生成变化检测器?这是个好问题,它们是由代码生成。 Angular 2 编译器为每个组件自动创建变化检测器,而且最终生成的这些代码 JavaScript VM友好代码。这也是为什么新的变化检测是快速的 (相比于 Angular 1.x 的 $digest)。基本上,每个组件可以在几毫秒内执行数万次检测。因此你的应用程序可以快速执行,而无需调
前朝楚水
2018/04/03
2.9K0
Angular 服务
本节课的重构完成之后,HeroesComponent 变得更精简,并且聚焦于为它的视图提供支持。这也让它更容易使用模拟服务进行单元测试。
HoneyMoose
2019/05/31
3.3K0
继续解惑,异步处理 —— RxJS Observable
接上一篇《Js 异步处理演进,Callback=>Promise=>Observer》,可能不少掘友对 Observer 还心存疑虑,本篇继续解惑~
掘金安东尼
2022/09/19
1.1K0
继续解惑,异步处理 —— RxJS Observable
angular 在指令里把组件当服务,并订阅组件的事件
- Module import { ExampleDirective , TabBodyComponent} from './example.component'; @NgModule({ declarations: [ExampleDirective , TabBodyComponent], providers: [ TabBodyComponent ] }) export class ExampleModule { } + AppComponent @Component({ select
treeNewBe
2020/06/16
1.3K0
RxJS Subject
观察者模式,它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。
阿宝哥
2019/11/06
2K0
一个Angular 5教程:一步一步指导实现你的第一个Angular 5应用程序
现在我们可以app.component.html用这个替换:Angular是由Google开发的AngularJS框架的新版本。它带有一个完整的重写,以及各种改进,包括优化构建和更快的编译时间。在这个Angular 5教程中,我们将从头开始构建一个笔记应用程序。如果您一直在等待学习Angular 5,本教程适合您。
WindCoder
2018/09/19
42.7K0
一个Angular 5教程:一步一步指导实现你的第一个Angular 5应用程序
相关推荐
augular 英雄之旅
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文