前言
RxJS 是 ReactiveX 库的 JavaScript 版本,在 Angular 中得到了广泛应用。它的作用是,将应用中的各种事件如 HTTP 请求、定时器、用户交互等当做流式数据处理,通过一系列的操作符进行处理和转换,从而达到高效、可维护和可组合的效果。
本文将结合示例代码,介绍 Angular 中 RxJS 的基本应用以及常用操作符的使用。
RxJS 基础
Observable 观察者
RxJS 中最基础的概念是 Observable 观察者。它可以看做一个数据源,会产生一些值并且通知器的订阅者,即 Observer 观察器。
-- -------------------- ---- ------- ------ - ---------- - ---- ------- ----- ---------- - --- --------------------- -- - ------------------- ------------------- ------------------- ------------- -- - ------------------- ---------------------- -- ------ --- ---------------------- ----- - -- --------------- ------ --- -- ------------------- --------- -- -- ------------------- ---
控制台输出:
1 2 3 4 Done
上述代码中,我们创建了一个 Observable 对象,并在其中通过 next 方法输出了 1,2,3 三个值。然后通过 setTimeout 定时器,产生了一个值为 4 的最终值并完成了输出。观察者通过传递一个对象作为参数来订阅 Observable。这个对象包含 Observer 的三个属性:next、error 和 complete。
Subject 主题
Subject 主题是一种实现了 Observable 和 Observer 两个接口的对象,它允许多个 Observer 同时监听同一个 Subject 对象,当 Subject 发生变化时,所有 Observer 都会收到通知。Subject 主题可以看做一种特殊的 Observable 对象,只不过它具备了多播的能力。
-- -------------------- ---- ------- ------ - ------- - ---- ------- ----- ------- - --- ------------------ ------------------- ----- --- -- ----------------------- ------ --- ------------------- ----- --- -- ----------------------- ------ --- ---------------- ----------------
控制台输出:
observerA: 1 observerB: 1 observerA: 2 observerB: 2
上述代码中,我们创建了 Subject 对象,并通过两次 subscribe 方法添加了两个 Observer。Subject 对象通过 next 方法传递数据,所有 Observer 监听到的数据相同。
操作符
RxJS 提供了许多操作符用于 Observable 数据流的转换和处理。以下是常用的一些操作符:
map
map 操作符用于将 Observable 中的数据逐一进行映射,并输出映射后的新数据。
import { of } from 'rxjs'; import { map } from 'rxjs/operators'; const source = of(1, 2, 3, 4, 5); const mapedSource = source.pipe(map(val => val * 2)); mapedSource.subscribe(console.log);
控制台输出:
2 4 6 8 10
上述代码中,我们通过源数据流 source 创建了一个 Observable 对象,并使用 map 操作符对其进行了转换,最后通过 subscribe 方法监听 map 映射后的数据流。
filter
filter 操作符用于对 Observable 数据流进行过滤,只输出符合条件的数据。
import { of } from 'rxjs'; import { filter } from 'rxjs/operators'; const source = of(1, 2, 3, 4, 5); const filteredSource = source.pipe(filter(val => val > 3)); filteredSource.subscribe(console.log);
控制台输出:
4 5
上述代码中,我们同样使用了源数据流 source 创建了一个 Observable 对象,并通过 filter 操作符过滤出大于 3 的数据流。
tap
tap 操作符用于查看 Observable 数据流的中间状态,类似于 console.log。
import { of } from 'rxjs'; import { tap } from 'rxjs/operators'; const source = of(1, 2, 3, 4, 5); const tappedSource = source.pipe(tap(val => console.log(`Before map: ${val}`)), map(val => val * 2), tap(val => console.log(`After map: ${val}`))); tappedSource.subscribe(console.log);
控制台输出:
-- -------------------- ---- ------- ------ ---- - ----- ---- - - ------ ---- - ----- ---- - - ------ ---- - ----- ---- - - ------ ---- - ----- ---- - - ------ ---- - ----- ---- -- --
上述代码中,我们在数据流的两个位置分别通过 tap 操作符打印出这个数据流经过 map 操作前后的状态。
在实际的 Angular 项目中,RxJS 核心库已经是预置的,我们只需要按需 import 即可。以下是一个简单的示例,实现了通过 HTTP 获取数据并渲染到页面中的功能。
首先,我们需要在 AppComponent 中定义一个 heroes 属性,用于存储从服务端获取的数据:
-- -------------------- ---- ------- ------ - --------- - ---- ---------------- ------ - ---------- - ---- ----------------------- ------------ --------- ----------- --------- - --------------- ---- --- ----------- ---- -- ---------- --------- ------- ----- - -- ------ ----- ------------ - ------- ---- ------------------- ----- ----------- - ---------------------------------------------------------------------- -- - ----------- - ----- --- - -
在上述代码中,我们在构造函数中使用 HttpClient 发起了一个 GET 请求,并在回调函数中将获取到的数据存入 AppComponent 的 heroes 属性中。最后,在组件的模板中使用了 Angular 的 ngFor 指令渲染出列表。
以上代码存在一个重大的问题,也就是当 HTTP 请求成功并获取到数据时,heroes 属性可能还没有被实例化。这时候 Angular 将不知道应该如何渲染模板,从而导致应用出错。为了解决这个问题,我们可以使用 Observable 对象来管理数据流,并将 heroes 加上一个默认值。
-- -------------------- ---- ------- ------ - --------- - ---- ---------------- ------ - ---------- - ---- ----------------------- ------ - ---------- - ---- ------- ------ - --- - ---- ----------------- ------------ --------- ----------- --------- - --------------- ---- --- ----------- ---- -- ---------- --------- ------- ----- - -- ------ ----- ------------ - ------- --- - --- -------- ---------------- ------------------- ----- ----------- - ------------ - ----------------- - ------- ------------ --------------- - ------ ------------------------------------------------------------- -------- -- - ----------- - ----- -- -- - -
以上代码中,我们将 heroes 改为了一个默认值为空的空数组,另外定义了一个 heroes$ 属性,类型为 Observable<any>。getHeroes 方法返回一个 Observable 对象,并使用 tap 操作符在数据流的中间状态中存储获取到的数据到 heroes 属性中。最后,在组件的构造函数中执行 getHeroes 方法,将数据流赋值给 heroes$ 属性。这样,当 Angular 初始化组件时,heroes 已经被定义为一个空数组,避免了应用出错的问题。
总结
RxJS 提供了一种高效、可维护和可组合的数据流处理方式,与 Angular 搭配使用可以带来更好的开发体验。在实际应用中,我们只需按需 import 操作符即可,非常方便实用。本文通过示例代码阐述了 RxJS 在 Angular 中的应用实战,并简要介绍了 Observable 观察者、Subject 主题和常用操作符的使用。希望读者能够通过本文对 RxJS 的应用有更深入的了解和学习,使其在实际开发中得到发挥。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64f04db2f6b2d6eab3a4a9bb