RxJS的入门指引和初步应用

RxJS是一个强大的Reactive编程库,提供了强大的数据流组合与控制能力,但是其学习门槛一直很高,本次分享期望从一些特别的角度解读它在业务中的使用,而不是从API角度去讲解。

RxJS简介

通常,对RxJS的解释会是这么一些东西,我们来分别看看它们的含义是什么。

Reactive

Lodash for events

Observable

Stream-based

什么是Reactive呢,一个比较直观的对比是这样的:

比如说,abc三个变量之间存在加法关系:

a = b + c

在传统方式下,这是一种一次性的赋值过程,调用一次就结束了,后面b和c再改变,a也不会变了。

而在Reactive的理念中,我们定义的不是一次性赋值过程,而是可重复的赋值过程,或者说是变量之间的关系:

a: = b + c

定义出这种关系之后,每次b或者c产生改变,这个表达式都会被重新计算。不同的库或者语言的实现机制可能不同,写法也不完全一样,但理念是相通的,都是描述出数据之间的联动关系。

在前端,我们通常有这么一些方式来处理异步的东西:

回调

事件

Promise

Generator

其中,存在两种处理问题的方式,因为需求也是两种:

分发

流程

在处理分发的需求的时候,回调、事件或者类似订阅发布这种模式是比较合适的;而在处理流程性质的需求时,Promise和Generator比较合适。

在前端,尤其交互很复杂的系统中,RxJS其实是要比Generator有优势的,因为常见的每种客户端开发都是基于事件编程的,对于事件的处理会非常多,而一旦系统中大量出现一个事件要修改视图的多个部分(状态树的多个位置),分发关系就更多了。

RxJS的优势在于结合了两种模式,它的每个Observable上都能够订阅,而Observable之间的关系,则能够体现流程(注意,RxJS里面的流程的控制和处理,其直观性略强于Promise,但弱于Generator)。

我们可以把一切输入都当做数据流来处理,比如说:

用户操作

网络响应

定时器

Worker

RxJS提供了各种API来创建数据流:

单值:of, empty, never

多值:from

定时:interval, timer

从事件创建:fromEvent

从Promise创建:fromPromise

自定义创建:create

创建出来的数据流是一种可观察的序列,可以被订阅,也可以被用来做一些转换操作,比如:

改变数据形态:map, mapTo, pluck

过滤一些值:filter, skip, first, last, take

时间轴上的操作:delay, timeout, throttle, debounce, audit, bufferTime

累加:reduce, scan

异常处理:throw, catch, retry, finally

条件执行:takeUntil, delayWhen, retryWhen, subscribeOn, ObserveOn

转接:switch

也可以对若干个数据流进行组合:

concat,保持原来的序列顺序连接两个数据流

merge,合并序列

race,预设条件为其中一个数据流完成

forkJoin,预设条件为所有数据流都完成

zip,取各来源数据流最后一个值合并为对象

combineLatest,取各来源数据流最后一个值合并为数组

这时候回头看,其实RxJS在事件处理的路上已经走得太远了,从事件到流,它被称为lodash for events,倒不如说是lodash for stream更贴切,它提供的这些操作符也确实可以跟lodash媲美。

数据流这个词,很多时候,是从data-flow翻译过来的,但flow跟stream是不一样的,我的理解是:flow只关注一个大致方向,而stream是受到更严格约束的,它更像是在无形的管道里面流动。

那么,数据的管道是什么形状的?

在RxJS中,存在这么几种东西:

Observable 可观察序列,只出不进

Observer 观察者,只进不出

Subject 可出可进的可观察序列,可作为观察者

ReplaySubject 带回放

Subscription 订阅关系

前三种东西,根据它们数据进出的可能性,可以通俗地理解他们的连接方式,这也就是所谓管道的“形状”,一端密闭一端开头,还是两端开口,都可以用来辅助记忆。

上面提到的Subscription,则是订阅之后形成的一个订阅关系,可以用于取消订阅。

下面,我们通过一些示例来大致了解一下RxJS所提供的能力,以及用它进行开发所需要的思路转换。

示例一:简单的订阅

很多时候,我们会有一些显示时间的场景,比如在页面下添加评论,评论列表中显示了它们分别是什么时间创建的,为了含义更清晰,可能我们会引入moment这样的库,把这个时间转换为与当前时间的距离:

const diff = moment(createAt).fromNow()

这样,显示的时间就是:一分钟内,昨天,上个月这样的字样。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/341a460e7f247d3949dbf854eedae115.html