原文:https://blog.csdn.net/qq_34414916/article/details/85194098

Observable

在开始讲服务之前,我们先来看一下一个新东西——Observable(可观察对象),是属于RxJS库里面的一个对象,可以用来处理异步事件,例如HTTP请求(实际上,在Angular中,所有的HTTP请求返回的都是Observable),或许,你以前接触过一个叫promise的东西,它们本质上面是相同的:都是生产者主动向消费者“push”产品,而消费者是被动接收的,但是他们两者还是有很大区别的:Observable可以发送任意多值,并且,在被订阅之前,它是不会执行的!这是promise不具备的特点,下面砸门来详细了解一下Observable

心法篇
Observable用于在发送方和接收方之间传输消息,为了更好地理解,你可以将这些消息看成是流
在创建Observable对象时,需要传入一个函数作为构造函数的参数,这个函数叫订阅者函数,这个函数也就是生产者向消费者推送消息的地方
在被消费者subscribe(订阅)之前,订阅者函数不会被执行,直到subscribe()函数被调用,该函数返回一个subscription对象,里面有一个unsubscribe()函数,消费者可以随时拒绝消息的接收!
subscribe()函数接收一个observer(观察者)对象作为入参
消息的发送可以是同步的,也可以是异步的
我们可以使用一系列的RxJS操作符,在这些消息被接收方接收之前,对它们进行一系列的处理、转换,因为这些操作符都是纯函数,没有副作用,可以放心使用,并不会产生期望之外的结果!
详细教程篇
1、observer(观察者)

有了可观察对象(发送方),怎么少得了observer(观察者)来观察可观察对象呢!observer是一个对象,其中包含三个属性:next,error,complete,它们都是函数

next:以接收的值作为入参,在正常情况下执行,可选
error:出错的情况下执行,可选
complete:传输完成的情况下执行,可选
当然,这都是由你自己代码决定的,(请继续往下阅读你就会明白)

2、初识Observable

我们先通过RxJS库中的(of)方法来创建一个Observable,而不是通过构造函数来创建(下一小节的内容)

在vscode中新建项目(文件夹),取名testRxJS,在该目录下新建一个.ts文件,取名teaching1.0.ts,内容如下

import { of } from "rxjs";

function f1() {
let observable = of(1, 2, 3);
observable.subscribe({ next: num => console.log(num) });
}
f1();

切换到vscode的命令行(ctrl+~),cd到本项目所在的文件夹,输入tsc .\teaching1.0.ts,然后输入node .\teaching.1.0.js,可以看到控制台有以下输出

代码解析

(注意,如果上面关于怎样运行ts程序,或者vscode操作你不熟悉的话,请先阅读vscode中使用TypeScript,以及vscode一些常用的快捷键,特别是箭头函数,如果你不熟悉的话,后面的内容将无法进行!)

RxJS中的of方法用于创建一个Observable,它会将其参数一个一个的发送给接收方,正如这里所看到的,它将1,2,3分别发送
subscribe()函数中接受一个observer对象,但这里,只定义了next方法,可以发现next方法接受一个参数,而这个参数就是生产者发送过来的值!然后将其打印在控制台上,(至于为什么这个值就是生产者发送的值,请继续阅读,其实说白了,是由你代码决定的,在下一小节,我们将会使用Observable的构造函数来定义一个Observable,并自己定义订阅者函数)
3、订阅者函数

上面说了很多这样的句子:请继续阅读,那么,在这一小节,我将揭晓谜底

同目录下新建一个teaching1.1.ts文件(注意,这篇博客牵涉的所有代码都在该目录(testRxJS)下,后面就不多讲了),内容如下

function f2() {
const observable = Observable.create(observer => {
try {
observer.next(1);
observer.next(2);
observer.next(3);
} catch (e) {
observer.error(e);
}
observer.complete();
});
const observer = {
next: num => console.log(num),
error: e => console.log(e),
complete: () => console.log('complete!!!')
}
observable.subscribe(observer);
}
f2();

用上面同样的方式运行,结果如下

可以发现,这运行效果同用of创建的Observable是一样的,只不过这里我还为observer定义了complete方法,所以它多输出了“complete!!!”。或许你也猜到了,这段代码就是of的内幕!!(注意,肯定不是of的源代码啊!),而且,如果出了错,就会被catch到,从而执行observer的error方法,通过这一小节,是不是对Observable有了更清晰的认识——原来都是有你的代码决定的,没有想象中的那么神秘

4、subscribe()(订阅)

在被消费者subscribe(订阅)之前,订阅者函数不会被执行,直到subscribe()函数被调用,该函数返回一个subscription对象,里面有一个unsubscribe()函数,消费者可以随时拒绝消息的接收!也就是说:在Observable调用subscribe函数之前,什么也不会发生,就像下面这段代码,控制台什么输出内容都没有

function f1() {
let observable = of(1, 2, 3);
}
f1();

直到你订阅这个observable对象,像下面这样

function f1() {
let observable = of(1, 2, 3);
observable.subscribe({ next: num => console.log(num) });
}
f1();

5、异步发送消息

其实,可以发现,上面一下节生产者发送消息的方式是同步的!这一小节,我们来个异步发送消息(等待2秒,再向消费者发送数字4),代码如下

function f2() {
const observable = Observable.create(observer => {
try {
let time = 0;
observer.next(1);
observer.next(2);
observer.next(3);
const intervalId = setInterval(() => {
console.log(`wait ${++time}s`);
}, 900)
setTimeout(() => { observer.next(4); clearInterval(intervalId) }, 2000);
} catch (e) {
observer.error(e);
}
// observer.complete(); // 注意不能立即调用complete函数,不然会终止消息传输
setTimeout(() => observer.complete(), 3000)
});
const observer = {
next: num => console.log(num),
error: e => console.log(e),
complete: () => console.log('complete!!!')
}
observable.subscribe(observer);
}
f2();

运行结果如下

代码解析

这里的代码可能有点复杂,但也是有基本元素组成:定时器、箭头函数,只要了解这两个知识点,这段代码应该就没有难度,但需要注意下面几点

complete不能立即调用,因为数字4的传输实在2秒后,如果你立即调用complete函数,就会中断传输,数字4也就接收不到了
注意到setInterval中的时间间隔并不是1000ms,我把它写成了900ms,可能是一些微小的时间延迟的原因,写成1000ms并不会产生期望的结果
最后产生的结果就是:数字4被异步发送了!!!
5、初识unsubscribe()函数

在这一小节,我们直接调用unsubscribe()函数,只为看看效果,下一小节,我们将自己写一个subscribe函数,并返回一个包含unsubscribe函数的对象,用于中断信息传输

function f3() {
const obs = Observable.create(observer => {
observer.next(1);
setTimeout(() => observer.next(2), 2000); // 等待两秒才发送下一个值
}); let suber = obs.subscribe({
next: x => console.log("接收到:", x),
}); setTimeout(() => suber.unsubscribe(), 1000); // 在一秒后取消订阅
}
f3();

运行结果如下

可以发现,接收方只接收到了数字1,

代码解析

因为数字2 在两秒钟后才会被发送,而消费者在1秒钟后便中断了消息传输,所以,控制台上面只打印了数字1
6、自定义subscribe()

看到这里,我想你应该也有些想法了,前面说过,Observable的subscribe函数返回一个subscription对象,其中有一个unsubscribe函数,用于取消订阅,你应该对subscribe函数的内部实现有着很多想法,现在,我们试着自己写一个!(在这里,我们就不需要Observable对象了,我们使用函数调用来模拟订阅),代码如下

function f4() {
function subscribe(observer) {
var intervalID = setInterval(() => {
observer.next('launch.....');
}, 1000); return {
unsubscribe: () => clearInterval(intervalID)
}
} var subscription = subscribe({ next: (x) => console.log(x) });
setTimeout(() => subscription.unsubscribe(), 5000);
}
f4();

运行结果如下

代码解析

这段代码的意思是:每隔1秒向控制台打印“launch....”,在第5秒的时候,取消打印(模拟取消订阅的过程)
可以发现,这个subscribe函数返回了一个对象!该对象中有一个unsubscribe函数!
通过这段代码,我们就模拟了Observable的subscribe函数的内部实现(仅仅是模拟而已)
7、使用RxJS中的操作符

在心法篇的时候,我就讲过这些操作符的重要作用以及优点,实际上,在开发实际应用的时候,你离不开它,在这里,我只举几个简单的例子,大概了解一下他们的用法就好

使用单个操作符
在这里,以map这个操作符为例,它可以接收可观察对象发送的值,并将其转换另外的形式,并以一个可观察对象发送这些新值,现在,我们来写一段有趣的代码:将原来的可观察对象发送的值全部转换为“hello world”,并订阅这个操作符返回的新的可观察对象,并输出值,代码如下

function f5() {
const observable = of(1, 2, 3);
const opt = map(num => 'hello world');
const newObservable = opt(observable);
newObservable.subscribe(data => console.log(data));
}
f5();

运行结果如下

可以发现map将1,2,3转换成了三个hello world并输出在控制台上,你也可以发现,这种方式代码结构并不是很清晰(特别是在有多个操作符的情况下),实际上,并不推荐这种写法,下面我们来看看另外一种更好的写法

使用多个操作符
我们可以使用管道(pipe),将多个操作符链接起来,并将操作符返回的结果组合成一个,这样,代码结构更清晰,在这里,我将把map、tap这两个操作符链接起来,使得,你既可以看到原可观察对象发送的值,你也可以看到转换后的结果

tip:tap操作符,可以理解为窥探,就是“不打扰”可观察对象发送的值,但是又可以取得这些值进行处理,常见的用法就是——调试功能

function f6() {
const observable = of(1, 2, 3);
const newObservable = observable.pipe(
tap(num => console.log(num)),
map(num => 'hello world')
);
newObservable.subscribe(data => console.log(data));
}
f6();
运行结果如下

这些写代码是不是很清晰呀!

---------------------
作者:数星星等天明
来源:CSDN
原文:https://blog.csdn.net/qq_34414916/article/details/85194098
版权声明:本文为博主原创文章,转载请附上博文链接!

Angular的Observable可观察对象(转)的更多相关文章

  1. Angular2 Observable 可观察对象

    可观察对象支持在应用中的发布者和订阅者之间传递消息.在需要进行事件处理,异步编程和处理多值的时候,可观察对象相对其他技术有显著的优点. 可观察对象是声明式的 —— 也就是说,虽然你定义了一个用于发布值 ...

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

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

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

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

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

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

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

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

  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. angular与avalon对复杂对象的修改

    angular的实现 <!doctype html> <html ng-app> <head> <script src="http://files. ...

随机推荐

  1. cpio建立、还原备份档

    1. 简介 加入.解开cpio或tar备份档内的文件 与tar相似,将文件归档到硬盘或磁带等存储设备中 2. tar比较 在所处理的文件类型方面,它比tar更全面,但也更复杂 cpio比tar更为可靠 ...

  2. Hexo主题开发

    序章 想要一个自己的知识管理系统,用了 Hexo ,但是没有发现自己心仪的主题,就自己做了一个.本文记录了制作的全过程.本人编码功底和前端知识并不是特别雄厚,希望能由此文引出各路大神的兴趣,以后制作出 ...

  3. Latex使用过程中的一些总结

    本文主要总结在使用Latex过程中遇到的一些问题及解决方案. 一:关于参考文献 1.如何在paper同一处用\cite命令同时引用多篇文献? 用\cite{bibtex1}\cite{bibtex2} ...

  4. Python3 if 变量variable SQL where 语句拼接

    最近在写python3的项目,在实际中运用到了根据 if 判断变量variable ,然后去拼接where子句.但是在百度.BING搜索中未找到合适的答案,这是自己想出来的典型php写法,这里做一下记 ...

  5. centos7删除Apache组件

    非特殊需要不要删除centos7中Apache等组件!首先查看centos中Apache版本(前面我们说了centos7删除PHP,centos7删除MariaDB,可能很多朋友会有疑问为什么要把所有 ...

  6. jQuery中关于Ajax的详解

    原文来自:http://developer.51cto.com/art/201205/335732.htm Ajax让用户页面丰富起来, 增强用户体验. Ajax是所有Web开发的必修课. 虽然Aja ...

  7. offsetWidth的bug

    #div1{width:200px;border:1px solid red;} 这个时候如果用 offsetWidth 提取 #div1 的宽  得到的值是 202: 也就是说 offsetWidt ...

  8. Gartner:2019 年 iPaaS 魔力象限

    http://www.199it.com/archives/869090.html 企业iPaaS产品支持越来越更广泛的使用场合,正迅速被企业采用以实现混合集成平台策略.这份魔力象限评估了17家供应商 ...

  9. mybatis框架-resultMap的自动映射级别-partial 和full的探讨

    现在我们做一个小实验,输出一下上一个案例中没有匹配的属性,注意哦,现在user类中是有内部嵌套的复杂数据类型的 运行结果: 注意到:现在居然连userPassword都打印不出来了,原因就是user类 ...

  10. html--前端基本标签内容讲解

    body里面分为两类标签:块级标签和内联标签. 1.块级标签:<p><h1><table><ol><ul><form><d ...