上次我们把 Observable 和函数进行类比,从函数的角度分析了 Observable 的一些特性,这次我们换一个角度,从流的角度理解 Observable。
从事件机制说起
Event
在浏览器中,事件机制是用户交互的基础,本质是程序各个组成部分之间的一种通信方式(或者叫观察者模式)。当事件源被触发,会调用相应的事件处理函数执行,并把事件对象(Event 对象,持有事件源的一些信息)传递给事件处理函数。没有Rx之前,事件一般是互相独立,各自调用的。
增加时间的维度
现在我们增加一个时间维度,在时间坐标上把同一个按钮上的单个事件点连成一条线:
有了时间维度,这条线看起来会是流动的,所以把他叫做一个流,接下来我们具体了解一下关于流的概念。
流stream
创建数据流
RxJS提供了各种API来创建数据流,我们先使用 create 进行自定义创建:
1 | const foo = Rx.Observable.create((observer) => { |
可以看到我们创建了一个定时器定时触发,并在定时器中定时回调 observer,吐出一个返回值,相当于我们通过迭代器模拟了一个定时发生的点击事件(事件源),返回值相当于 Event(事件对象),而 observer 则相当于 EventListener(事件处理的监听器),单个事件串联起来就形成了流。
还记得我们上次提到的生产者和消费者的概念吗?上例中,迭代器作为生产者不断生成数据形成流,observer 作为消费者等待回调,虽然 Observable 本质上还是一个函数,但是从形式上来看,Observable 就像一个管道对接了生产者和消费者。
数据的管道
数据流这个词,很多时候,是从data-flow翻译过来的,但flow跟stream是不一样的,我的理解是:flow只关注一个大致方向,而stream是受到更严格约束的,它更像是在无形的管道里面流动。
而 Observable 就是限制 stream 流动的无形管道中的一种。,从整个过程来看, Observable 对接了生产者和消费者,也就是作为管道对接了流,从生产者角度来说,Observable 是使得数据流可以被观测的一种特殊函数,于是有了一个新的名字:可观测对象,而从消费者的角度来说,它就是流的代表,可以直接被叫做流。
Everything is a stream
不只是 Events,我们可以把一切输入都当做数据流来处理,比如说:
- 用户操作
- 网络响应
- 定时器
- Worker
产生新流
当产生了一个流后,我们可以通过操作符(Operator)对这个流进行一系列加工操作,然后产生一个新的流:
1 | Rx.Observable.fromEvent(window, 'click') |
map
把流转换成了一个每次产生1的新流,然后 scan
类似 reduce
,也会产生一个新流,最后这个流被订阅。最终实现了每次点击累加1的效果。
可以用一个效果图来表示该过程:
lodash for stream
这时候回头看,其实RxJS在事件处理的路上已经走得太远了,从事件到流,它被称为lodash for events,倒不如说是lodash for stream更贴切,它提供的这些操作符也确实可以跟lodash媲美。
总结
在两篇文章中,我们分别从函数和流的角度了解了 Observable。本质上讲,Observable 是一种特殊的函数, 同时也是 RxJS 的一个核心类型,可以收集单个事件形成流来统一处理。
我觉得复杂的东西都有多种特性,就像光的波粒二象性一样,我们学习时不要拘泥于某种特性去归类,因为其可能具有不同事物的多种特性,需要我们从不同角度来描述和理解。
最后再分享一篇文章,希望能帮助更好的理解Observable:如何从头开始创建 Observable。