# 伍.3.1 什么是响应式编程？

**响应式编程简称RP（Reactive Programming）**，是一种面向**异步**（asynchronous）**数据流**（Data Stream）的编程范式。其实，这并不是什么新东西，而是新瓶装旧酒，把编程中常用的[发布-订阅模式](https://coffe1891.gitbook.io/frontend-hard-mode-interview/id-7/1.-jing-dian-she-ji-mo-shi/7.1.5)发扬光大，然后形成一整套可供我们高效解决问题的编程范式。

## 01.什么是数据流（Data Stream)

接上面说的，其实数据流也不是新东西。举个例子，我们在浏览器中单击一个按钮，这个点击事件(event)就是一个真正的异步数据流（asynchronous data stream），以下简称流。在这个流里面，你可以观察一些对象，也可以做一些响应处理，总之随你喜好。

而且，我们可以把任意东西包装成流，而不限于点击事件、或者鼠标滑过事件。流无处不在，信手拈来，任意东西都可以成为流：变量、用户的操作、属性、缓存、数据结构等等。譬如：假想你的微博首页是一个流，那么你就可以监听它的变化，并且根据需要采取阅读与否的决定（做出响应）。

最重要的是，我们将获得令人惊叹的功能工具箱，这个工具箱里面有一系列函数，可以帮助我们组合、创建、过滤这些流。是的，这时候函数式编程就派上用场了。如果不了解函数式编程，可以看本书之前的相关章节。

流可以用作另一流的输入， 甚至多个流也可以用作另一个流的输入。 您可以合并两个流。 您可以过滤流以获得另一个只包含您感兴趣的事件的流。您可以将数据值从一个流映射到另一个新流。

既然流对于响应式（Reactive）如此重要，那么，让我们从熟悉的“单击按钮”这个事件流开始细致地研究它们。接下来我们看一个图，因为看起来像一颗颗弹珠，通常这类型的图叫弹珠图。

![弹珠图](https://1680353414-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LnlixiOMXyluGpXDGGs%2F-MD8FEdmnPWjeJ0l1zNH%2F-MD8FePCIEvc6mb7io0-%2F5.3.1.1.1.png?alt=media\&token=2f07f1fd-9186-4197-8dda-5ab67bb2e5b6)

如上图，水平从左至右的箭头线表示时间线。流是**按时间顺序排列的一系列进行中的事件**， 它可以含有三种不同的东西：

* 一个值（是某种类型的）。也就是上图的各色弹珠。
* 一个错误（也可能没有）。也就是上图的红叉。
* 一个“完成”信号（也可能没有）。也就是上图中时间线上的竖线。 例如，当包含该按钮的当前窗口或视图关闭时，可以认为流发出了“完成”信号。

接下来，让我们做点有趣的事情：创建从原始点击事件流转换而来的新点击事件流。

## 02.流的转换

在[函数式编程](https://coffe1891.gitbook.io/frontend-hard-mode-interview/2.-han-shu-shi-bian-cheng/5.2.1#07-han-zi-functor)我们介绍过带有map方法的函子（比如Array就是函子，实现了map方法）。map方法接受一个函数，让该函数处理函子里面的数据，输出另一个函子。这段说得比较学术化，但其实说白了，就是将原数据通过map转换一下，得到一个新的数据，如此而已。

针对流，我们也可以类似的这么做。输入一个流，通过map（等）函数处理一下，变成一个新的流。

//todo

## 03.“我为什么要考虑通过响应式编程解决问题？”

上面介绍了一些响应式编程的技术特征，那么响应式编程的必要性是什么呢？可以先简单讲一下。后面再以实例展开叙述。

响应式编程提升了代码的抽象层次，让我们可以专注于处理业务逻辑，而不必关注太多细枝末节的事情：比如服务器端数据变化后，前端变量值的实时获取、及时更新其他有关的变量、以及界面的再次渲染。使用响应式编程会让这些细碎的事情变得更简单。

在与大量数据事件相关的、UI事件高度交互的现代Web应用程序和移动应用程序中，响应式编程的好处更加明显。10年前，与网页的交互基本上是向后端提交一个form表单，后端处理好之后，再向前端执行“粗暴的”渲染逻辑以呈现变化。现代的应用程序已经变得更加实时：修改单个表单字段可以自动触发到后端的保存，对某些内容的“点赞”可以实时反映给其他已连接的用户……等等。

如今，现代应用程序具有各种实时事件，可以为用户带来高度交互的体验。我们需要适当处理这些问题的工具，而响应式编程就是一个不错的选项。

## 参考文献

{% hint style="info" %}
<https://gist.github.com/staltz/868e7e9bc2a7b8c1f754>
{% endhint %}
