数据驱动(data-driven
) 是指将传递的数据和行为进行分离。这也是为什么RxJS能够以相同的范式来处理不同类型的数据源(比如数组,字符串,事件,AJAX请求等等)的核心原理。
- 以数据作为中心,将数据从行为系统中分离出来,用数据去驱动业务
- 没有数据,行为将不起作用,数据给行为带来升级,行为响应数据的变化,而不是等待数据的到来
- 流(stream)只是一个传递过程,如果没有用户订阅,或者数据传递进来,流将保存闲置状态

数据生产者 producers
数据的产生有不同的原因,这样造成数据源的来源有很多种情况。
- 生产者有各种各样的形态和大小,
Event Emitter
就是比较常见的一种生产者,它们用于响应鼠标点击或者网络请求,同时他们也是基于时间的数据源 - 当处理不同类型的数据源,我们应当自然会想到使用不同类型的方式来处理。不如
event emitters
需要使用命名event handlers 来处理,Promises
需要一个连续传递的thenable
函数来处理;setTimeout
需要回调函数来处理;Arrays
需要通过循环来迭代数据
但是Rx对不同类型的数据进行了包装处理,这样我们可以以相同的范式来处理不同类型的数据源,也就是说
不同类型的数据源在事件驱动(或流驱动)的棱镜下观察都是一样的,
就好比Rx.Observable 是一个锤子,把其余所有的数据类型当作钉子
识别不同类型的数据源
数据源广义的可以分为以下几类:
- Emitted Data
- Static Data
- Generated Data
1.Emitted Data
发生数据是一种外部与系统交互产生的结果。可以来自与用户交互,比如点击鼠标,也可以是系统事件,比如读取文件。
比如你请求数据,未来某个时间点,你接收到数据,对于这种情况, Promises
可能是一个好的解决方案。
2.static data
静态数据已经存在或者显示在系统(内存)中,比如 array
,string
。人工的单元测试数据就划分到这一类型数据中。
3.Generated data
产生的数据是指间隔的或最终产生的数据,比如时钟每小时都会报时。
比如无限产生的数据,不可能将其全部存储在内存中,值应当动态的被创建和产生给需要的使用者。
数据类型的划分
根据以下2个维度可以将数据划分为4类:
- 值的多少: 单值(比如数字), 多值(比如数组)
- 数据的处理方式: 同步的, 还是异步的

1.single-value && synchronous
这是最简单的数据类型,比如数字,一个对象,我们可以通过 Rx.Observable.of
将其转换为一个 Obserable类型。
但是一般处理简单类型的数据使用Observable,有点杀鸡用牛刀的味道,一般只有我们希望将简单类型的值和其它类型的流整合在一起时,才使用Obserable
2.multi-value && synchronous
我们可以将单值集合起来形成集合,主要是数组类型。
我们可以使用 Rx.Obserable.from
将集合类型转换为Obserable类型
3.single-value && asynchronous
对于异步的情况,正是RxJS大放异彩的地方。
对于异步的情况,我们只能保证到吗在未来某个时间被处理,因此,后面的代码块不能依赖前面代码块的执行。
对于单值异步的情况,使用 Promises
进行处理最好了,在RxJS中可以使用 Rx.Observable.fromPromise()
将promises转换为Observable类型。
Rx.Observable.fromPromise($.ajax('/data'))
4. multi-value && aynchronous
这种类型的数据一般时间会作为数据来源的因子。比如DOM事件,不知道未来什么时候会产生。
对这种数据的处理我们需要 混合迭代器和promise模式,通常的处理方式是使用 EventEmitter
进行处理。
RxJS在javascript原有的EventEmitter的基础上对其进行了改进。可以使用 Rx.Observable.fromEvent()
将EventEmitter 转换为Observbale类型
PUSH-BASED && PULL-BASE MODEL
迭代器使用的 pull-based
模型, 而RXJS使用的是 push-based
模型。

-
pull-based
对下面情况是非常拥有的: 当我们知道一个字能从计算后立即返回时。对于不知道值什么时候返回或者有没有值返回的情形,pull-based
模型就失效了,比如鼠标点击,使用者是不知道下一次点击事件什么时候反生,或者发不发生 -
push-based
模式中,生产者负责创建下一个数据,消费者只需要监听新的事件即可

Observable && Observer
被观察者和观察者
- 业务逻辑,比如值如何产生,怎么被发送归属于Observable,而所有的渲染细节,是否使用插件什么的处理逻辑归属于observer中的调度者
- 要记住,无限事件发送,比如DO事件,将不会触发 complete() 方法,因此,取消订阅取决于使用者,可以采取手动取消订阅或者自动取消订阅机制

Observable 基本api
被观察者本质上一个函数
下面用简单的方式来描述observable
const observable = events => { // 时间队列
const INTERVAL = 1 * 1000;
let schedulerid;
return { // 返回一个包含 'subscribe' 方法的对象
subscribe: oberver => { // 接收 observer 对象作为参数
schedulerid = setInterval(() => {
if (events.length === 0) { // 如果没有时间处理了
observer.complete();
clearInterval(schedulerid);
schedulerid = undefined;
} else { // 如果有事件反生, 使用 observer.next()方法进行处理
observer.next(events.shift());
}
}, INTERVAL);
return {
unsubscribe: () => { // subscribe 方法返回一个unsubscribe 方法用于取消订阅
if (schedulerid) {
clearInterval(schedulerid);
}
}
};
}
}
}

总结
主要将了以下几个方面
- RxJS采用了数据驱动的方式,数据和业务逻辑分离
- RxJs对javascript的EventEmitter进行了改进,使其可以对事件进行推送
- Push-based 和 Pull-based 方式的差异
- 根据值的多少和处理方式2个维度,将数据源划分为4类
- 简单Observable apis的介绍
- Rx.Observable.of()
- Rx.Observable.from()
- Rx.Observable.fromPromise()
- Rx.Observable.fromEvent()
- Observable 和 Observer 之间的关系简单介绍
网友评论