可观察对象支持在应用中的发布者和订阅者之间传递消息。在需要进行事件处理,异步编程和处理多值的时候,可观察对象相对其他技术有显著的优点。

  可观察对象是声明式的 —— 也就是说,虽然你定义了一个用于发布值的函数,但是在有消费者订阅它之前,这个函数并不会实际执行。 订阅之后,当这个函数执行完或取消订阅时,订阅者就会收到通知。

创建 Observable(可观察对象)

  Rx.Observable.create 是 Observable 构造函数的别名,它接收一个参数:subscribe 函数。

  使用 Observable 构造函数可以创建任何类型的可观察流。 当执行可观察对象的 subscribe() 方法时,这个构造函数就会把它接收到的参数作为订阅函数来运行。 订阅函数会接收一个 Observer 对象,并把值发布给观察者的 next() 方法。

如下:创建一个Observable,并每隔一秒向观察者发送‘hi’:

  1. var observable = Rx.Observable.create(function subscribe(observer) {
  2. var id = setInterval(() => {
  3. observer.next('hi')
  4. }, 1000);
  5. });

注意:Observables 可以使用 create 来创建, 但通常我们使用所谓的创建操作符, 像 offrominterval、等等。

如下:

  1. Observable.of(...items) —— 返回一个 Observable 实例,它用同步的方式把参数中提供的这些值发送出来。
  2. Observable.from(iterable) —— 把它的参数转换成一个 Observable 实例。 该方法通常用于把一个数组转换成一个(发送多个值的)可观察对象。

执行Observable

Observable 执行可以传递三种类型的值:

  • "next" :用来处理每个送达值。在开始执行后可能执行零次或多次。比如数字、字符串、对象,等等。
  • "error" :可选。用来处理错误通知,发送一个 JavaScript 错误 或 异常。错误会中断这个可观察对象实例的执行过程 。
  • "complete" :用来处理执行完毕(complete)通知。

  "Next" 通知是最重要,也是最常见的类型:它们表示传递给观察者的实际数据。

  "Error" 和 "Complete" 通知可能只会在 Observable 执行期间发生一次,并且只会执行其中的一个,一旦发送,那么之后不会再发送任何通知了。

下面是 Observable 执行的示例,它发送了三个 "Next" 通知,然后是 "Complete" 通知:

  1. //用try..catch 捕获异常
    var observable = Rx.Observable.create(function subscribe(observer) {
  2. try {
  3. observer.next(1);
  4. observer.next(2);
  5. observer.next(3);
  6. observer.complete();
       observer.next(4); // 因为违反规约,所以不会发送
  7. } catch (err) {
  8. observer.error(err); // 如果捕获到异常会发送一个错误
  9. }
  10. });

清理 Observable 执行

  因为 Observable 执行可能会是无限的,并且观察者通常希望能在有限的时间内中止执行,所以我们需要一个 API 来取消执行。因为每个执行都是其对应观察者专属的,一旦观察者完成接收值,它必须要一种方法来停止执行,以避免浪费计算能力或内存资源。

  当你订阅了 Observable,你会得到一个 Subscription ,它表示进行中的执行。只要调用 unsubscribe() 方法就可以取消执行。

  1. var observable = Rx.Observable.from([10, 20, 30]);
  2. var subscription = observable.subscribe(x => console.log(x));
  3. // 稍后:
  4. subscription.unsubscribe();

  当我们使用 create() 方法创建 Observable 时,Observable 必须定义如何清理执行的资源。你可以通过在 function subscribe() 中返回一个自定义的 unsubscribe 函数。

  1. var observable = Rx.Observable.create(function subscribe(observer) {
  2. // 追踪 interval 资源
  3. var intervalID = setInterval(() => {
  4. observer.next('hi');
  5. }, 1000);
  6.  
  7. // 提供取消和清理 interval 资源的方法
  8. return function unsubscribe() {
  9. clearInterval(intervalID);
  10. };
  11. });
  12.  
  13. //这里返回一个函数声明
  14. var subscription=observable.subscribe((x)=>console.log(x));
  15. //执行取消订阅
  16. subscription.unsubscribe();

Observer (观察者)

  观察者是由 Observable 发送的值的消费者。观察者只是一组回调函数的集合,每个回调函数对应一种 Observable 发送的通知类型:nexterror 和 complete 。下面的示例是一个典型的观察者对象:

  1. var observer = {
  2. next: x => console.log('Observer got a next value: ' + x),
  3. error: err => console.error('Observer got an error: ' + err),
  4. complete: () => console.log('Observer got a complete notification'),
  5. };
  6.  
  7. observable.subscribe(observer);
  8.  
  9. //观察者只是有三个回调函数的对象,每个回调函数对应一种 Observable 发送的通知类型。

Subscription (订阅)

  Subscription 基本上只有一个 unsubscribe() 函数,它不需要任何参数,这个函数用来释放资源或去取消 Observable 执行占用的资源。

  Subscription 还可以合在一起,这样一个 Subscription 调用 unsubscribe() 方法,可能会有多个 Subscription 取消订阅 。你可以通过把一个 Subscription 添加到另一个上面来做这件事:

  1. var observable1 = Rx.Observable.interval(400);
  2. var observable2 = Rx.Observable.interval(300);
  3.  
  4. var subscription = observable1.subscribe(x => console.log('first: ' + x));
  5. var childSubscription = observable2.subscribe(x => console.log('second: ' + x));
  6.  
  7. subscription.add(childSubscription);
  8.  
  9. setTimeout(() => {
  10. // subscription 和 childSubscription 都会取消订阅
  11. subscription.unsubscribe();
  12. }, 1000);

  执行时,我们在控制台中看到:

  1. second: 0
  2. first: 0
  3. second: 1
  4. first: 1
  5. second: 2

  Subscriptions 还有一个 remove(otherSubscription) 方法,用来撤销一个已添加的子 Subscription 。

Subject (主体)

  Subject 是一种特殊类型的 Observable,它允许将值多播给多个观察者,所以 Subject 是多播的,而普通的 Observables 是单播的(每个已订阅的观察者都拥有 Observable 的独立执行)。

  每个 Subject 都是 Observable 。 - 对于 Subject,你可以提供一个观察者并使用 subscribe 方法,就可以开始正常接收值。从观察者的角度而言,它无法判断 Observable 执行是来自普通的 Observable 还是 Subject 。

  在 Subject 的内部,subscribe 不会调用发送值的新执行。它只是将给定的观察者注册到观察者列表中,类似于其他库或语言中的 addListener的工作方式。

  每个 Subject 都是观察者。 - Subject 是一个有如下方法的对象: next(v)error(e) 和 complete() 。要给 Subject 提供新值,只要调用 next(theValue),它会将值多播给已注册监听该 Subject 的观察者们。

  在下面的示例中,我们为 Subject 添加了两个观察者,然后给 Subject 提供一些值:

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

  下面是控制台的输出:

  1. observerA: 1
  2. observerB: 1
  3. observerA: 2
  4. observerB: 2

  因为 Subject 是观察者,这也就在意味着你可以把 Subject 作为参数传给任何 Observable 的 subscribe 方法,如下面的示例所展示的:

  1. var subject = new Rx.Subject();
  2.  
  3. subject.subscribe({
  4. next: (v) => console.log('observerA: ' + v)
  5. });
  6. subject.subscribe({
  7. next: (v) => console.log('observerB: ' + v)
  8. });
  9.  
  10. var observable = Rx.Observable.from([1, 2, 3]);
  11.  
  12. observable.subscribe(subject); // 你可以提供一个 Subject 进行订阅

  执行结果:

  1. observerA: 1
  2. observerB: 1
  3. observerA: 2
  4. observerB: 2
  5. observerA: 3
  6. observerB: 3

  使用上面的方法,我们基本上只是通过 Subject 将单播的 Observable 执行转换为多播的。这也说明了 Subjects 是将任意 Observable 执行共享给多个观察者的唯一方式。

Subject的三种变体类型:

  • BehaviorSubject :主要用来表示随着时间的流逝,值会改变的情况。比如生日是Subject,而生日就是BehaviorSubject。
  • ReplaySubject :当有新的订阅者订阅时,可以指定回放的值得个数,或者以 window time (以毫秒为单位) 规定范围内发生的值。
  • AsyncSubject : 当被观察者的值推送完成时,才将最后一个值发送给观察者。类似于last ()操作符。

多播的 Observables

  多播 Observable 在底层是通过使用 Subject 使得多个观察者可以看见同一个 Observable 执行。

  多播 Observable” 通过 Subject 来发送通知,这个 Subject 可能有多个订阅者,然而普通的 “单播 Observable” 只发送通知给单个观察者。

  在底层,这就是 multicast 操作符的工作原理:观察者订阅一个基础的 Subject,然后 Subject 订阅源 Observable 。下面的示例与前面使用 observable.subscribe(subject) 的示例类似:

  1. var source = Rx.Observable.from([1, 2, 3]);
  2. var subject = new Rx.Subject();
  3. var multicasted = source.multicast(subject);
  4.  
  5. // 在底层使用了 `subject.subscribe({...})`:
  6. multicasted.subscribe({
  7. next: (v) => console.log('observerA: ' + v)
  8. });
  9. multicasted.subscribe({
  10. next: (v) => console.log('observerB: ' + v)
  11. });
  12.  
  13. // 在底层使用了 `source.subscribe(subject)`:
  14. multicasted.connect();

  multicast 操作符返回一个 Observable,它看起来和普通的 Observable 没什么区别,但当订阅时就像是 Subject 。multicast 返回的是 ConnectableObservable,它只是一个有 connect() 方法的 Observable 。

  connect() 方法十分重要,它决定了何时启动共享的 Observable 执行。因为 connect() 方法在底层执行了 source.subscribe(subject),所以它返回的是 Subscription,你可以取消订阅以取消共享的 Observable 执行。

Angular2 Observable 可观察对象的更多相关文章

  1. Angular的Observable可观察对象(转)

    原文:https://blog.csdn.net/qq_34414916/article/details/85194098 Observable 在开始讲服务之前,我们先来看一下一个新东西——Obse ...

  2. RxJS 简介:可观察对象、观察者与操作符

    RxJS 简介:可观察对象.观察者与操作符 对于响应式编程来说,RxJS 是一个不可思议的工具.今天我们将深入探讨什么是 Observable(可观察对象)和 observer(观察者),然后了解如何 ...

  3. [译]Rxjs&Angular-退订可观察对象的n中方式

    原文/出处: RxJS & Angular - Unsubscribe Like a Pro 在angular项目中我们不可避免的要使用RxJS可观察对象(Observables)来进行订阅( ...

  4. wex5 教程 之 图文讲解 可观察对象的集群应用与绑定技术

    一 前言: wex5官方教程里,开篇即以一个input输入,output即时输出的例子,为我们展现了一个概念:可观察对象.在以后我的项目开发中,将大量运用可观察对象. 那么,问题来了: 1. 可观察对 ...

  5. ngx通讯之可观察对象实现

    1.公共服务 //test.service.ts import {Injectable} from '@angular/core'; import {Subject} from 'rxjs/Subje ...

  6. 可观察对象(Observable)

    最简示例: export class AppComponent { title = 'angular-tour-of-heroes'; // Create an Observable that wil ...

  7. Java基础之一组有用的类——Observable和Observer对象(Horrific)

    控制台程序. Obserable类提供了一个有趣的机制,可以把类对象中发生的改变通知给许多其他类对象. 对于可以观察的对象来说,类定义中需要使用java.util.Observable类.只需要简单地 ...

  8. Object.observe() 观察对象

    这个对象方法可以用来异步观察对javascript对象的改动: // Let's say we have a model with data var model = {};   // Which we ...

  9. QPointer,QSharedPointer,QWeakPointer的区别与使用例子(QSharedPointer类似Delphi里的引用计数,是强引用,而QWeakPointer是弱引用,不影响原始对象的引用计数,相当于是在暗中观察对象,但保持联系,需要的时候就会出现)

    QPointer is a template class that provides guarded pointers to Qt objects and behaves like a normal ...

随机推荐

  1. Android蓝牙——HID开发

    代码地址如下:http://www.demodashi.com/demo/13891.html 原文地址: https://blog.csdn.net/VNanyesheshou/article/de ...

  2. HDU 5389 Zero Escape(dp啊 多校)

    题目链接:http://acm.hdu.edu.cn/showproblem.php? pid=5389 Problem Description Zero Escape, is a visual no ...

  3. DirectX.DirectSound声音播放资料

    参考:https://msdn.microsoft.com/en-us/library/windows/desktop/bb318665(v=vs.85).aspx Microsoft DirectS ...

  4. 转mosquitto auth plugin 编译配置

    配置使用 mysql 作为 be (back end) 使用config.mk 配置编译参数 cp config.mk.in config.mk 修改 安装 mysql sudo apt-get in ...

  5. Tomcat服务器配置https协议(Tomcat HTTPS/SSL 配置)

    通常商用服务器使用https协议需要申请SSL证书,证书都是收费的,价格有贵的有便宜的.它们的区别是发行证书的机构不同,贵的证书机构更权威,证书被浏览器否决的几率更小. 非商业版本可以通过keytoo ...

  6. appium 1.6.3 + ios 10.2 + xcode 8.2.1 真机运行safari

    启动appium 命令: appium --address "127.0.0.1" --session-override --pre-launch --debug-log-spac ...

  7. unity, Rigidbody.constraints

    一,同时施加多个限制: 用按位或(bitwise OR)实现,例如: GetComponent<Rigidbody>().constraints=RigidbodyConstraints. ...

  8. [Jobdu] 题目1139:最大子矩阵

    题目描述: 已知矩阵的大小定义为矩阵中所有元素的和.给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵.比如,如下4 * 4的矩阵 0 -2 -7 09 2 -6 2-4 1 -4 ...

  9. OC06 -- 字典

    一. 创建不可变字典的方式: //字典的字面量,前key后value NSDictionary *dic =@{@"1":@"2",@"3" ...

  10. Animation.Sample用法介绍

    无意中翻到这篇问答LINK,发现了Sample的用法 如果想让Animation在编辑器状态下预览,也可以用这个接口 当你想要直接获得动画的运行结果,而不是等帧数执行到这,这时候就得调用Sample: ...