ES6 rxjs Observable

一、拉取(Pull)  、 推送(Push)

介绍 Observable 之前,要先了解两个设计模式:
  • Observer Pattern - (观察者模式)

  • Iterator Pattern - (迭代器模式)

    这两个模式是 Observable 的基础。

Observable(可观察对象)是基于推送(Push运行时执行(lazy)的多值集合。下方表格对Observable进行了定位(为解决基于推送的多值问题):下表是对Observable的使用场景进行的简单的定位。

MagicQ 单值 多值
拉取(Pull) 函数 遍历器
推送(Push) Promise Observable

拉取(Pull) V.S. 推送(Push)

拉取推送是数据生产者和数据消费者之间通信的两种不同机制。

何为拉取? 在拉取系统中,总是由消费者决定何时从生产者那里获得数据。生产者对数据传递给消费者的时间毫无感知(被动的生产者,主动的消费者)。

JavaScript函数是典型的拉取系统:函数是数据的生产者,对函数进行调用的代码(消费者)从函数调用后的返回值中拉取单值进行消费。

// 函数是数据的生产者
let getLuckyNumber = function() {
    return 7;
};

/* let代码段是数据的消费者,
 * getLuckyNumber对调用时间毫无感知。 
 */
let luckNumber = getLuckyNumber();

何为推送? 在推送系统中生产者决定何时向消费者传递数据,消费者对何时收到数据毫无感知(被动的消费者)。

现代JavaScript中Promise是典型的推送系统。作为数据生产者的Promise通过resolve()向数据消费者——回调函数传递数据:与函数不同,Promise决定向回调函数推送值的时间。


MagicQ 生产者 消费者
拉取 被动: 在被请求时产生数据 主动: 决定何时请求数据
推送 主动: 控制数据的产生逻辑 被动: 获得数据后进行响应


二、Observable(被观察者)

实例:首先是创建一个被观察者( observable)。当 observable被订阅后,会立即( 同步地)推送 123 三个值;1秒之后,继续推送 4这个值,最后结束( 推送结束通知):

var observable = Rx.Observable.create(function (observer) {
  observer.next(1);
  observer.next(2);
  observer.next(3);
  setTimeout(() => {
    observer.next(4);
    observer.complete();
  }, 1000);
});

为得到observable推送的值,我们需要订阅(subscribe)这个Observable:(通过.subscribe这个方法进行订阅行为

var observable = Rx.Observable.create(function (observer) {  // 此处是创建一个被观察者observable
  observer.next(1);
  observer.next(2);
  observer.next(3);
  setTimeout(() => {
    observer.next(4);
    observer.complete();
  }, 1000);
});

console.log('just before subscribe');
observable.subscribe({  // 此处是对observable 进行订阅,即创建一个观察者observe
  next: x => console.log('got value ' + x),
  error: err => console.error('something wrong occurred: ' + err),
  complete: () => console.log('done'),
});
console.log('just after subscribe');

程序执行后,将在控制台输出如下结果:


just before subscribe
got value 1
got value 2
got value 3
just after subscribe
got value 4
done

三、Observable 是函数概念的拓展

Observable 更像是一个不需要传入参数的函数,它拓展了函数的概念使得它可以返回多个值。

看看下面的例子:


function foo() {
    console.log('Hello'); 
    return 42;
}


console.log('before');
console.log(foo.call());  // foo.call()等同于直接掉用foo()
console.log('after');


显然可以看到以下输出:

"before"
"Hello"
42
"after"

Observable的行为完全一样:

var foo = Rx.Observable.create(function (observer) {  
    console.log('Hello');  
    observer.next(42);
});


console.log('before');
    foo.subscribe(function (x) { 
    console.log(x);
});

console.log('after');

输出结果为:

"before"
"Hello"
42
"after"

订阅 foo完全是同步的,与函数的调用一样。

Observable可以异步或者同步地产生数据。

那Observable 与函数的不同之处在哪里? Observable可以在一个时间过程中‘返回’多个值,而函数却不能。在函数中你不可以这么做:

function foo() {
  console.log('Hello');
  return 42;
  return 100; // 这个语句永远不会被执行。
}

虽然函数只能有一个返回值,但是在Observable中你完全可以这么做:

var foo = Rx.Observable.create(function (observer) {
  console.log('Hello');
  observer.next(42);
  observer.next(100); // 返回另一个值
  observer.next(200); // 返回另一个值
});

console.log('before');
foo.subscribe(function (x) {
  console.log(x);
});
console.log('after');

输出结果如下:


"before"
"Hello"
42
100
200
"after"

你甚至可以异步地返回值:

var foo = Rx.Observable.create(function (observer) {
  console.log('Hello');
  observer.next(42);
  observer.next(100);
  observer.next(200);
  setTimeout(() => {
    observer.next(300); // happens asynchronously
  }, 1000);
});

console.log('before');
foo.subscribe(function (x) {
  console.log(x);
});
console.log('after');

输出结果:


"before"
"Hello"
42
100
200
"after"
300

结论:

  • func.call() 意味着“同步地给我一个值”

  • observable.subscribe() 意味着“不管是同步或者异步,给我一些值”


四、Observable 深度解析

Rx.Observable.createObservable 构造函数的别名,接受一个参数: subscribe函数。

除了使用 create 创建Observable,我们通常还使用 创建操作符 , 如 of from interval , 等来创建Observable。
例:Rx.Observable.of(...)

Observable在执行过程中,可以推送三种类型的值:

  • "Next" 通知: 实际产生的数据,包括数字、字符串、对象等

  • "Error" 通知:一个JavaScript错误或者异常

  • "Complete" 通知:一个不带有值的事件
    “Next” 通知是最重要和常用的类型:表示事件传递给观察者的数据。错误和完成通知仅会在执行阶段推送其一,并不会同时推送错误和完成通知。

在Observable的执行过程中,0个或者多个“Next”通知会被推送。在错误或者完成通知被推送后,Observable不会再推送任何其他通知。

下面代码展示了Observable 在执行过程中推送3个“Next” 通知然后结束:

var observable = Rx.Observable.create(function subscribe(observer) {
  observer.next(1);
  observer.next(2);
  observer.next(3);
  observer.complete();
});

Observable 严格遵守 Observable 契约,后面值为4的“Next” 通知永远不会被推送:

var observable = Rx.Observable.create(function subscribe(observer) {
  observer.next(1);
  observer.next(2);
  observer.next(3);
  observer.complete();
  observer.next(4); // 由于违法契约,4不会被推送
});

使用try/catch块包裹 subscribe 代码是一个很赞的想法,如果捕获了异常,可以推送错误通知:



var observable = Rx.Observable.create(function subscribe(observer) {
  try {
    observer.next(1);
    observer.next(2);
    observer.next(3);
    observer.complete();
  } catch (err) {
    observer.error(err); // 捕获异常后推送错误通知
  }
});
  

你可能感兴趣的:(ES6 rxjs Observable)