RxJS在Angular的使用场景实例

概述

本文将会先对RxJS进行阐述解释,然后会向大家逐一介绍一下以下的四个场景和使用到的语法:

  1. Angular 框架中使用async pipe将视图流直接映射为视图,以及tapmap的使用;
  2. 同一可观察对象的多个订阅的解决方案 -share()运算符;
  3. 使用debounceTime()switchMap()运算符实现动态搜索,以及switchMap()结合interval()做接口轮询;
  4. 使用takeUntil()避免内存泄漏。

希望通过这四个简短的案例场景的解读,帮助大家对于RxJS有更好的体验感,并在日常的开发场景当中思考并寻找到属于自己的应用场景。

RxJS是什么

RxJS(JavaScript 响应式扩展)是一个使用可观察量进行响应式编程的库,可以更轻松地编写异步或基于回调的代码。

RxJS 提供了 Observable 类型的实现。该库还提供了用于创建和使用可观察量的实用函数。这些实用函数可用于:

  • 将异步操作的现有代码转换为可观察量
  • 迭代流中的值
  • 将值映射到不同类型
  • 过滤流
  • 组合多个流

说人话,就是:让网页视图能够正确的响应相关的事件。

  1. 描述数据流
  2. 组合与转换数据流
  3. 消费数据流进行视图的更新

场景示例

原料准备:

1.在线运行环境:stackblitz.com/

2.在线mock数据请求:dummyjson.com/docs/produc...

场景1:Angular 框架中使用async pipe将视图流直接映射为视图

在线示例:RxJS-场景1:async pipe

在上面的例子中,变量products$从http请求中获取数据流。一旦数据处于可观察(observable)的形式,除了基础的数据展示,我们还可以继续进行流操作/合并/链接等。

在 RxJS 中,理解生产者(Producer)消费者(Consumer)的概念至关重要。这里的 Angular 模板是一个消费者 - 它订阅(在可观察变量上调用 .subscribe() 方法)products$,并且每次执行此操作时,它都会创建一个生产者(https 请求)以将数据获取到可观察流中。

在Angular 框架中,可以直接使用async pipe(在 html 模板中,片段| async),它负责将可观察值中的值解析为普通数据,直接将视图流映射为视图。

如果希望更加考究一些,可以使用*ngIf配合else制作loading加载效果。虽然在实际项目开发中,我们所用的组件库一般都带有loading的配置项。

在线示例:RxJS-场景1:async pipe + else Template

另外,展开说一下文件里用到的tapmap

tap常常会和console.log结合使用,能够帮助我们监控.pipe管道中方法和方法之间的数据表现是什么样的。如下图所示:我们可以在控制台看到接口返回的数据格式。

在这个例子中,我们只需要将products字段渲染在视图上,所以加上了map((data) => data.products),表示只需要返回其中products字段。通常,当我们从后端获取的数据不能直接显示的时候,就可以使用map来执行数据的过滤。

场景2:同一可观察对象的多个订阅的解决方案 - share() 运算符

在线示例:RxJS-场景2:share()

当我们建立多个请求相同内容的订阅者,或者模板中多次使用相同的可观察变量时,可以用share()"共享"流。

1.建立多个请求相同内容的订阅者:制作一个变量productsWithApple$渲染在页面上。

2.在模板中多次使用相同的可观察变量:在模板上多次渲染products$

场景3:使用debounceTime()switchMap()运算符实现动态搜索

搜索功能是几乎每个网络应用程序中极其常见的功能。当输入框里输入/网络生成太多请求时,switchMap()运算符会取消请求。通过取消请求,来节省浏览器/客户端的 CPU 功率,还可以节省实际的服务器资源。

同时,输入框里是连续输入事件,如果每次都响应会触发太多的后端请求,我们希望短时间内多次输入只触发最后一次,可以结合debounceTime()运算符来实现。

场景3:RxJS-场景3:switchMap() 和 debounceTime()

另外,switchMap()interval()结合,也可以更好的撰写轮询请求。(关于为什么直接用RxJS的interval()而不是setInterval可以看这篇文档:《Rxjs的interval和timer与Js的setInterval和setTimeout》)

主要的撰写思路就是:当下一次轮询执行请求的时候,上一个请求还在pending没有返回,就取消上一个请求。

typescript 复制代码
component.ts

// 定时刷新告警数据
violationListInterval$: Observable<number> = interval(3000);

constructor() {
    this.violationListInterval$.pipe(switchMap(() => this.api.getData()))
}

场景4:使用takeUntil()避免内存泄漏

通常,我们手动订阅subscribe,但忘记取消订阅。当然,在Angular 内置的async pipe中(即场景1中的例子)会为我们自动取消订阅。

有两种办法来取消订阅。第一种,我们可以将subscribe()的结果推入一个数组,然后在ngOnDestroy()中遍历数据执行unsubscribe();第二种办法,就是使用takeUntil(),在ngOnDestroy()中关闭所有订阅。

这里着重说一下takeUntil的使用。

RxJS 中,可以使用 takeUntil来控制另外一个 Observable 对象数据的产生。使用 takeUntil,上游的数据直接转手给下游,直到takeUntil的参数吐出一个数据或者完结。

就像一个水龙头开关,一开始是打开的状态,上游的数据一开始直接流到下游,只要 takeUntil 一旦触发吐出数据,水龙头立刻关闭。

利用这点,可以在订阅时时,在管道中添加 takeUntil,在组件销毁时吐出数据,这样这些订阅就会立刻关闭,也就达到回收内存的作用。

注意,takeUntil 一定要放在管道的最后,来提示之前所有的执行逻辑做一次销毁。否则,订阅无法被正常清除。

更多细节的讲解,可以看下这篇文章:《使用 takeUntil 操作符管理 Angular 组件的订阅》

资料

RxJS Quick Introduction (with Examples) for Beginner-Level Angular Developers

RxJs - Stream Analogs in Real Life (2021)

RxJS and Angular: Why and how to use

Observable 防腐层项目实战

相关推荐
余生H1 个月前
JS异步编程进阶(二):rxjs与Vue、React、Angular框架集成及跨框架状态管理实现原理
javascript·vue.js·react.js·angular·rxjs·异步编程
进二开物8 个月前
原来 RxJS 是这样处理复杂数据流
前端·后端·rxjs
chuckchen8 个月前
前端开发中的响应式编程
响应式编程·rxjs
进二开物9 个月前
给 RxJS 的 Ajax 的功能拦截器
前端·javascript·rxjs
进二开物9 个月前
为什么能用 RxJS 取代 Redux ?
前端·javascript·rxjs
进二开物10 个月前
RxJS 夯实基础 | 想要的这里都有
前端·后端·rxjs
偏安zzcoder10 个月前
Angular系列教程之观察者模式和RxJS
前端·观察者模式·angular.js·rxjs
non_hana1 年前
简单聊聊RxJS中的Observable类和其pipe()方法
前端·typescript·rxjs
进二开物1 年前
详解 RxJS 创建型可观察对象操作符
前端·后端·rxjs
进二开物1 年前
Canvas 与 RxJS 制作动画-控制移动
前端·后端·rxjs