我们知道Observable是个容器,里面包含着数据,数据从何而来?
静态数据
我们日常重度使用的string
和array
都属于此范畴。
动态数据
比如我们用ES6中的generator
生成斐波那契数列,比如通过RESTful api调用返回的数据。
Observables发送事件,Observer异步地接收事件,这可以让我们的应用在有大量事件产生的时候保持响应能力。强调一下,RxJS不是仅面向客户端js的,在服务端同样可以使用。看下代码:
Rx.Observable.from(<数据源>)
.operator1(...)
.operator2(...)
.operator3(...)
.subscribe(<处理最终结果数据>)
再强调两个事情,第一,observables是个不可变数据类型,像string一样;第二,observables不仅仅代表了当前时刻的数据,也代表了未来某时刻的数据。
何时何地用RxJS
世间没有万能药,RxJS也一样,只在适合它的地方使用它。我们把程序按照两个维度划分成一个田字表格,横向是单值,多值,纵向是同步,异步。
单值,同步
用Rx.Observable.of来包装单值同步数据:
Rx.Observable.of(2017)
一旦有消费者消费,此值马上被发送出去。这种情况下使用RxJS显得有点重了,除非我们想进行合并流的操作。
多值,同步
用Rx.Observable.from来包装多值同步数据:
Rx.Observable.from([1, 2, 3])
from()函数可能是RxJS中最常用的之一了。同步在这里是啥意思呢?就是说1处理完了才能处理2,2处理完了才能处理3。如果1处理得慢,2必须等着,以此类推。
单值,异步
这个情况其实就是Promise。RxJS提供了函数可以无缝地和Promise整合到一起。
const one = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 3000);//模拟3秒延迟
});
//这个时候Promise中的代码已经在运行了
Rx.Observable.fromPromise(one)
.map(value => value = value + 1);
.subscribe(result => {
console.log(result);
});
console.log("程序结束");
由于是异步程序,一运行就会打印“程序结束”,3秒后将打印2。然而用Observable包装一层有啥意义?意义在于Promise是无法重新运行的,而Observable可以,并且还可以让它运行很多次,这是通过内嵌Observable来实现的,我们后面会讲到。
多值,异步
这个场景就是我们常说的事件驱动的异步编程。比如DOM事件以及NodeJS中的EventEmitter。如何使用RxJS包装DOM事件,如下图:
这里我用的是https://jsfiddle.net/。点击span标签,在控制台打印出span标签中的href属性值。
EventEmitter的包装在这里我们就暂时不讲了,以后碰上再说。感兴趣的可以看下RxJS的文档。
拉模型与推模型
迭代器就是基于拉的获取数据的代表。最有代表性的示例就是利用ES6中的Generator来生成斐波那契数列。Generator的教程请参见http://es6.ruanyifeng.com/#docs/generator。基于拉的获取数据的方式就是我想要数据的时候才去获取数据,是主动的去获取数据。
而Observable是基于推的获取数据方式的。数据会主动推送给我,我被动地接收数据做出响应。
以上说了那么多,想表明一件事就是,RxJS可以用同样的方式来处理同步和异步编程,并且把如何产生数据和如何消费数据各自独立出来。
我们可以把一切东西都转换成Observable,但是应该不应该就要视情况而定了。比如转换字符串大小写,直接用string的方法就可以了。RxJS中的任何操作都会有性能损失。