发布于 2026-01-06 0 阅读
0

RxJS入门

RxJS入门

小溪、瀑布、流水、流动、绿色、风景、苔藓

无论你是 JavaScript 新手还是经验丰富的开发者,你很可能都听说过 RxJS。

RxJS 是目前最流行的 JavaScript 库之一。本文将简要介绍 RxJS 的基本概念以及如何在应用程序中使用它。

历史

所以在开始之前,了解 RxJS 的历史会很有帮助。

这一切都始于响应式扩展(Reactive Extensions ,简称 ReactiveX)。ReactiveX 最初由Erik Meijer提出,是观察者模式的一种实现。在其开发之后,围绕 .NET 和 JavaScript 等主流语言,相继开发了一系列相关的编程库。

RxJS 是 JavaScript 的响应式扩展(Reactive Extensions)实现。RxJS项目最初由Matthew Podwysocki等人发起,是一个独立的开源项目。大约从 RxJS 版本 5 开始,Ben Lesh等人对项目进行了改进,使其成为如今的样子。

RxJS库同时实现了观察者模式迭代器模式

RxJS 库也使用函数式编程来实现用于管理事件序列(流)的操作符和函数。想要深入了解函数式编程,我强烈推荐观看 Russ Olsen 在 GOTO 2018 上的视频。

命令式与声明式

当人们讨论 RxJS 时,通常会提到命令式编程和声明式编程。

命令式代码指的是以特定方式编写的代码。这种代码需要你手动控制流程,类似于Promise 的工作方式。

声明式编程指的是使用已声明的函数来执行操作。这种编程方式依赖于能够定义事件流的“纯”函数。在 RxJS 中,这种编程方式体现在可观察对象运算符上。

这些定义稍后会在本文中变得更加清晰,但在这里介绍一下也无妨。

可观测变量

解释 RxJS 时,最简单的方法通常是先展示代码。

大多数人通常都熟悉以下实现的 Promise:

没什么特别的,只是使用了标准的“resolve/reject”语法。Promise 完成后,输出信息会写入控制台。

现在请将此与以下内容进行比较:

哇!那是什么?那是 RxJS!如果你仔细观察,你会发现它采用了声明式编程实践,首先定义可观察对象,然后使用观察者中的不同钩子,例如 `on` nexterror`on` 和 `on` complete

我稍后会在本文中再次提到这个例子,但首先想介绍一下。

RxJS 的工作原理是什么?

因此,在开始学习 RxJS 之前,最好先了解一些定义:

  • 可观测对象= 已定义的事件流
  • 订阅= 代表事件的实际执行流程(发起订阅基本上就是“开启”执行)。
  • 运算符= 是“纯”函数,可以调用带有订阅的流。它们有不同的形式,既可以创建流,也可以在可管道化的流中复制流。
  • Subject是一个事件发射器,可用于多播。它们是特殊的,用于在程序中注入发射器。
  • 调度器= 它们有助于处理并发,实际上是 RxJS 中更高级的主题。我只是为了完整性才在这里提及。

更多信息和示例请参阅此处的官方 RxJS 入门指南

既然我们已经引入了这些词汇,现在就可以正式讨论我之前举的例子了。

可观测变量(再次)

现在让我们回到我之前展示的代码:

这是一个很好的例子,因为它展示了 Observable 的实现。

首先,你需要定义 Observable ,next然后complete,当我启动执行流程时,subscribe我会包含有关如何执行该流程的定义:

  • next = 执行console.log从流中返回的内容。
  • error =console.log如果流中发生错误,则执行此操作
  • complete =done执行完成后向控制台输出信息

这是直接定义可观察对象的一种方法。每个观察者都有三个钩子:`on` nexterror`on` 和complete`on`,您可以使用它们来定义执行行为。

操作员

Observables 很棒,但 RxJS 还提供了运算符,使定义 Observables 变得更加容易。

操作分为两种类型:

  • 创建运算符= 具有预定义行为的已生成可观察对象
  • 可管道操作符= 使用语法“.pipe”返回其他可观察对象的可观察对象

以下是一个创建运算符的实际应用:

这里我们使用of运算符按顺序发出 `a` 10、` 20b`、`c` 和 `d`的值30。这只是一个非常基础的例子,但它能让你了解如何使用它在流中发出一组值,而无需手动定义观察者钩子。

以下是一个管道运算符的实际应用示例:

所以这里的情况稍微复杂一些,但我相信你能弄明白。

  1. 我们使用之前提到创建运算 of来生成值流a,,,bc
  2. 接下来,我们将输出传递of管道运算符。 mergeMap
  3. 然后我们mergeMap创建一个新的可观察对象并将其传递给interval
  4. 然后,在延迟 1 秒后interval获取输出和每个值。console.log

所以,这基本上创建了一个包含pipeable操作符的流程。原始源 Observable 用于创建一个带有附加逻辑的新 Observable。

更简单的理解方式是,stream这里定义了一个“a”。与数据流一起使用的每个管道都会增加价值。

更形象地理解管道运算符的方式是,将其比作水流经一组管道。每根管道都会为水增加价值,直到水流结束。

从下图可以直观地看到这一流程:

为了更直观地展示 RxJS 的流程图,许多人会使用 Marble Diagrams(大理石图)。它们乍一看可能有点复杂,但如果你按照 RxJS 指南学习如何阅读,它们会非常有帮助。我建议你查看此处操作符页面底部的 RxJS 指南

订阅和内存泄漏

因此,开发者在使用 RxJS 时遇到的一个大挑战是订阅过程中的内存泄漏。

内存泄漏是指您忘记“取消订阅”某个数据流,而该进程仍在继续运行并消耗大量内存。内存泄漏会迅速耗尽浏览器内存,并降低应用程序的运行速度。

最佳解决方案是始终确保.unsubscribe为你的可观察对象设置一个接口。你也可以依赖框架中预置的机制,例如 Angular 的asyncpipe。

以下代码会造成内存泄漏:

这段代码很容易修复,只需添加一个setTimeout在设定的时间间隔后取消订阅流的函数,如下所示:

我之前在 RxJS DEVTO 博客上发表过一篇关于这个主题的文章,标题是“处理订阅的常用方法”,链接在此。强烈建议您有时间阅读一下。

高级主题

到目前为止,我们只介绍了一些基本的执行流程。如果将 RxJS 操作符组合起来,就可以用少量代码实现相当复杂的功能。

当你从单个 Observable 创建一组 Observable 时,就会遇到挑战。这被称为高阶 Observable。RxJS提供了一些操作符来帮助你简化这种情况,例如:

我不会在这里深入探讨高阶可观察对象,因为我认为这超出了入门文章的范围。不过,我强烈建议您查阅RxJS 指南中关于运算符的部分,其中对此有更详细的讨论

我在RxJS DEVTO 博客文章“从 Promises 到 Observables”中也介绍了更高级的主题(点击此处阅读)。在那篇文章中,我详细讲解了如何设置一个scan操作符来合并多个 HTTP 调用。

我还建议阅读RxJS DEVTO 博客网站上的文章,其中有更多关于 Observable 的高级案例和讨论。

延伸阅读

我在这篇文章中只是浅尝辄止地介绍了 RxJS 的一些功能。网上还有很多优秀的资料和视频,提供了深入的讲解和示例。

我建议先看看这些视频:

闭幕致辞

希望这篇文章对你学习 RxJS 有所帮助。在本文中,我详细介绍了 RxJS 的概念以及在程序中使用它的方法。

感谢阅读这篇文章!欢迎在 Twitter 上关注我@AndrewEvans0102,也欢迎访问andrewevans.dev查看我的最新项目。

文章来源:https://dev.to/andrewevans0102/getting-started-with-rxjs-2dl0