没对象?那就开始使用Observable对象吧~

前(xia)言(che)

在前端开发中,有的人觉得简单,熟练常用的css属性,写个界面信手捏来;牢记jquery文档,dom,ajax一把梭。有的人觉得难,浏览器兼容惹人头大,JS怪异语法琢磨不透…
而我个人觉得,前端的一个难点在于如何优雅的处理前端的数据。

生产者与消费者

说到数据,那么首先得明白两个概念,生产者与消费者。

很明显,生产者,即生产数据的,消费者即使用数据的。

而在JS中,常见的数据生产者有哪些呢?

  1. function 函数
  2. Iterator 迭代器
  3. Promise 承诺?
  4. Observable 可观察者对象

生产者的区别

要明白4个生产者区别,那么有必要先理解下关于”推“与”拉“两个概念。

  • “拉”:数据的消费者决定何时从生产者那里获取数据,生产者不能意识到何时数据被发送给消费者
  • “推”:数据的生产者决定何时将数据发送给消费者,消费者不能意识到何时获取数据

而他们的在“推拉”的区别如下:

pull拉 function Iterator
push推 Promise Observable

当然,除了这个区别外,他们的返回值个数也是不同的

单值 function Promise
多值 Iterator Observable

同步与异步

同步 funtion Iterator
同/异步 Promise Observable

惰性求值与及早求值

惰性求值 function Iterator Observable
及早求值 Promise

列了那么多区别,其实对与obserbable对象,可以总结为:可观察对象是更一般的,零参的函数,但是允许返回多个值使得其更加一般化。

observable的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import Rx from 'rxjs/Rx';
var observable = Rx.Observable.create(function(observer){
observer.next('hello')
});
// 第一种订阅方法
observable.subscribe({
next: (val)=>{console.log(val)}, // hello
error: ()=>{},
complete: ()=>{}
})
// 第二种订阅方法
obserbable.subscribe(
function(val){console.log(val)}, // hello
function(){},
function(){}
)

通过调用create方法,可创建一个可观察对象。

源码中create方法实现为:

1
function(subscribe){return new Observable(subscribe)}

通过subscribe方法,使观察者去订阅可观察对象。其中subscribe方法有两种方式,一种是传递一个拥有next,error,complete属性的观察者对象;另一种是传递3个参数,分别是next,error,complete的回调函数。

当观察者(即subscribe的参数)订阅了可观察者,可观察者才开始分发内容(即执行创建可观察者对象时传入的函数)。

Subject

Subject是允许值被多播到多个观察者的一种特殊的Observable。

1
2
3
4
5
6
7
8
9
var subject = new Rx.Subject();
subject.subscribe({
next: (v) => console.log('observerA: ' + v)
});
subject.subscribe({
next: (v) => console.log('observerB: ' + v)
});
subject.next(2);
subject.next(3);

依次输出:

1
2
3
4

为什么要使用subject?
可以看出,若使用observable create,可观察者分发内容的时机是观察者订阅可观察对象时,这样就不能发放一个内容时,多个观察者可以同时获取到,比如依次执行next(2)和next(3),那么依次输出为 2,3 2,3。
那么使用subject的好处有:

  1. 可以自定义分发内容的时机,实现多播
  2. 是观察者,也是可观察者,可作为一个中介
1
2
3
4
5
var subject = new Rx.Subject();
subject.subscribe({next:(val))=>{console.log(val)}}); // 中介与观察者
var obserbable = Rx.Observable.from([12,3,4]); // from作用是构建一串数据依次分发
obserbable.subscribe(subject); // 被观察者与中介

多播

因为普通的可观察者对象,是不能进行在多播的,而借助subject,可让被观察者成为一个可以多播可观察者对象。

1
2
3
4
5
6
var source = Rx.Observable.from([2,3,4]);
var subject = new Rx.Subject();
var multicaseted = source.multicast(subject);
multicaseted.subscribe(v=>{console.log(v)});
multicaseted.subscribe(v=>{console.log(v)});
multicaseted.connect(); // 手动connect

使用引用计数 refCount

避免显示调用connect, 使用引用计数 refCount, 它可以追踪可观察对象的订阅者数量,从增加1时,则会自动调用分享被观察对象的执行,而从1 至 0 时,则自动取消执行。

1
2
3
4
5
var source = Rx.Observable.interval(500);
var subject = new Rx.Subject();
var refCounted = source.multicast(subject).refCount();
refCounted.subscribe(...);
refCounted.subscribe(...);

总结

  1. 可观察对象属于”推“体系的数据流,0参数,惰性求值,支持同异步,允许返回多个值使得其更加一般化的函数。
  2. Subject是一种特殊的Observable。常作为中介使用,Subject使可观察对象和观察者之间更加多样和灵活。
  3. 多播是可观察者对象对订阅的观察者同时分发内容的一种行为