原文地址: https://segmentfault.com/a/1190000012669794

引言

  开发ngx(angular 2+)应用时,基本上到处都会用到rxjs来处理异步请求,事件调用等等。所以经常会使用Subject来处理源源不断的数据流,比如input text change, toast notification等等。
  这都要依赖于Subject本身既可以是Observable也可以是Observer,也就是说subject既可以作为一个数据源,也可以本身成为一组订阅者的代理
  但当处理更加复杂的业务需求时,仅仅用Subject可能无法满足要求,这个时候就考虑一下rxjs提供的其他Subject Class了, 例如BehaviorSubject ReplaySubject AsyncSubject, 接下来我们就来看一下他们跟Subject有什么区别,各自有什么特点,在什么时候更适合使用。

  [文中代码均使用typescript]

Subject

  首先我们来创建一个Rxjs Subject, 数据的类型是number

  let subject1: Subject<number> = new Subject<number>(); // (A)

  然后我们使用Subjectnext方法来emit(发射)1条数据

  subject1.next(100); (B)

  接下来对subject1创建两个订阅,在subscription中直接打印接受到的数据

   subject1.subscribe((res: number) => console.info("subjectA ", res)); // (C) subject1.subscribe((res: number) => console.info("subjectB ", res));

  接下来我在发射两条数据

   subject1.next(200); (D)subject1.next(300);

  好了,接下来我们就来看看console里面会打印出什么结果。
  也许有的同学会觉得结果是这样的,因为Subject可以接收源源不断的数据嘛,所以无论发射多少次数据,订阅者都能接收到。

//output
subjectA 100
subjectB 100 subjectA 200 subjectB 200 subjectA 300 subjectB 300

  这个结果不太对
  因为Subject的订阅者只有在订阅后,才能接收到数据源发射过来的值。
  所以在代码块C中, 订阅者在订阅数据源subject1之前, 无论代码块B执行多少次, 订阅者也只能收到代码C之后发射的数据。

  正确的结果应该是:

//output
subjectA 200
subjectB 200 subjectA 300 subjectB 300

  这种情况在项目里经常能遇到,有时候我明明从数据源发射一个数据,但在订阅者拿到的值却是undefined或者null, 这就是因为订阅者是在数据源发射之后创建的,自然无法接收到数据了。
  假如我们想在订阅者创建之后,无论什么时候都能拿到数据, 这应该怎么办呢? 那就要考虑使用BehaviourSubject了。

BehaviorSubject

  我们依旧使用刚才的例子, 创建一个BehaviorSubject, 默认值设为0. BehaviorSubject需要给个默认值
  然后发射一条数据100,创建一个订阅者,再发射一条数据200,再创建一个订阅者,最后发射一条数据300。
  代码如下:

let subject2: BehaviorSubject<number> = new BehaviorSubject<number>(0); subject2.next(100); subject2.subscribe((res: number) => console.info("behavior-subjectA ", res)); subject2.next(200); subject2.subscribe((res: number) => console.info("behavior-subjectB ", res)); subject2.next(300);

  这个时候结果就应该是:

//output
behavior-subjectA 100
behavior-subjectA 200
behavior-subjectB 200
behavior-subjectA 300 behavior-subjectB 300

  由于BehaviorSubject是可以存储最后一条数据或者初始默认值的, 所以无论订阅者什么时候订阅到数据源subject2上, 都能接收到数据。
  所以针对订阅者behavior-subjectA, 他订阅的时候,数据流里最后一条数据是100, 他能立即接收到。 然后依次能接收到最新的数据200300
  针对订阅者behavior-subjectB, 他订阅的时候,数据流里最后一条数据是200, 他能立即接收到。 然后只能能接收到最新的数据300了。

  BehaviorSubject给予我们的便利就是,无论何时订阅到数据源,始终都能拿到最新的或者初始的数据,但也只能拿到一条数据,但当我们处理input text change事件时,需要拿到用户输入的所有字符,也就是数据流的所有数据,BehaviorSubject就无能为力了,这个时候我们考虑使用ReplaySubject了。

ReplaySubject

  我们依旧使用刚才的例子, 创建一个ReplaySubject, 发射两条数据100和200,创建一个订阅者,再发射一条数据300,再创建一个订阅者,最后发射一条数据400。
  代码如下:

let subject3: ReplaySubject<number> = new ReplaySubject<number>();
subject3.next(100); subject3.next(200); subject3.subscribe((res: number) => console.info("replay-subjectA ", res)); subject3.next(300); subject3.subscribe((res: number) => console.info("replay-subjectB ", res)); subject3.next(400);

  控制打印的结果将是:

//output
replay-subjectA 100
replay-subjectA 200
replay-subjectA 300
replay-subjectB 100 replay-subjectB 200 replay-subjectB 300 replay-subjectA 400 replay-subjectB 400

  ReplaySubject会存储数据流中的所有数据无论何时订阅到subject3,订阅者都能获取了订阅之前数据流里的所有数据,然后依旧获取到接下来获取的到的新数据。
  就像ReplaySubject类名的中Replay, 一旦订阅到数据源,就会将数据流像放电影一样重新放一遍给你。

  订阅者replay-subjectA订阅到subject3的时候,数据流里已经有了100和200, 接收并打印出来。
  最后打印新数据300和400.
  订阅者replay-subjectB订阅到subject3的时候,数据流里已经有了100,200,300, 接收并打印出来。最后打印新数据400.

  接下来就要说下最后一种Subject了,也就是AsyncSubject

AsyncSubject

  AsyncSubjectBehaviorSubject`ReplaySubject`有些类似,但不同的是AsyncSubject只会存储数据流里的最后一条数据, 而且只有在数据流complete时才会将值发布出去
  AsyncSubject主要是用来处理异步操作,当数据源是异步请求或者事件处理时,可能会发射出很多数据,如果我们只希望数据源的异步操作完成的时候,订阅者才能接收到值,这个时候就可以使用AsyncSubject了。
  接下来我们看个例子,
  创建一个AsyncSubject, 然后发射数据,创建订阅者,再发射数据。。。

let subject4: AsyncSubject<number> = new AsyncSubject<number>();
subject4.next(100); subject4.next(100); subject4.subscribe((res: number) => console.info("async-subjectA ", res)); subject4.next(300); subject4.subscribe((res: number) => console.info("async-subjectB ", res)); subject4.next(400); subject4.subscribe((res: number) => console.info("async-subjectC ", res)); subject4.complete(); subject4.subscribe((res: number) => console.info("async-subjectD ", res)); subject4.next(500);

  最后的结果就应该是:

//output4
async-subjectA 400
async-subjectB 400 async-subjectC 400 async-subjectD 400

  由于subject4AsyncSubject, 只有在complete的时候才会向订阅者publish数据,而且只publish最后一次数据,所以无论订阅者何时订阅数据源,都可以接收到最后一次数据。
  但为什么没有打印出500呢,因为数据源已经complete了,你就无法再发射新数据了。

总结

  最后来总结一下四种Subject的特点,理解好的各自的特点,在项目开发中可以处理很多棘手的需求,同时也会避免很多问题的发生。

转载于:https://www.cnblogs.com/lnlvinso/p/11228724.html

【Rxjs】 - 解析四种主题Subject相关推荐

  1. 解析四种大数据文件格式

    众所周知,Apache Spark支持许多种不同的数据格式,其中包括:无处不在的CSV格式.对于Web友好的JSON格式.以及常被用于大数据分析的Apache Parquet和Apache Avro. ...

  2. 解析四种红颜薄命的女人面相特征,长得漂亮命却苦

    http://item.btime.com/44oq9vcakjf9fs8r7opo520ao02?from=wifimini 有的女人有令人羡慕的天生丽质,也有这让人仰慕的才华,更曾有过如公主女神般 ...

  3. 【Swagger】四种主题更换方式及页面对比

    1.默认主题 1)依赖 <dependency><groupId>io.springfox</groupId><artifactId>springfox ...

  4. @Import注解:导入配置类的四种方式源码解析

    微信搜索:码农StayUp 主页地址:https://gozhuyinglong.github.io 源码分享:https://github.com/gozhuyinglong/blog-demos ...

  5. JavaScript内存管理机制以及四种常见的内存泄漏解析

    转自:http://geek.csdn.net/news/detail/238898 原文:How JavaScript works: memory management + how to handl ...

  6. 四种Java线程池用法解析

    四种Java线程池用法解析 本文为大家分析四种Java线程池用法,供大家参考,具体内容如下 http://www.jb51.net/article/81843.htm 1.new Thread的弊端 ...

  7. java四种xml_Java中四种XML解析技术

    转载自 http://www.it.com.cn/f/edu/053/27/93819.htm 在平时工作中,难免会遇到把 XML 作为数据存储格式.面对目前种类繁多的解决方案,哪个最适合我们呢?在这 ...

  8. 详解Java解析XML的四种方法

    http://developer.51cto.com  2009-03-31 13:12  cnlw1985  javaeye  我要评论(8) XML现在已经成为一种通用的数据交换格式,平台的无关性 ...

  9. IOS中Json解析的四种方法

    2019独角兽企业重金招聘Python工程师标准>>> 作为一种轻量级的数据交换格式,json正在逐步取代xml,成为网络数据的通用格式. 有的json代码格式比较混乱,可以使用此& ...

最新文章

  1. apkplug插件托管服务简化与简介-05
  2. SpringBoot2.0之 个性化Banner
  3. 如何直接在github上预览html网页效果
  4. 为什么德国人工作这么慢,但效率却很高?
  5. 【mysql】SCOPE_IDENTITY 和 @@IDENTITY的区别
  6. vue.jsr入门_JSR 365更新:深入CDI 2.0
  7. 记录——《C Primer Plus (第五版)》第十章编程练习第十一题
  8. linux下查看系统硬件,Linux 查看系统硬件信息 Linux 查看系统硬件信息(实例详解)...
  9. Ubuntu下安装tensorBroad的全过程
  10. RunAs 增强性扩展命令(支持自动提交密码,安全授权)
  11. java中的冒泡排序和交换排序
  12. 什么是云?云里雾里——最流行的云时代
  13. 使用JavaVisualVM远程监控JVM虚拟机
  14. 智能车改舵机中值步骤_智能车制作全过程(飞思卡尔)
  15. 计网 - 内容分发网络 : CDN 回源的工作机制初探
  16. 计算机怎么执行程序代码,代码如何运行?
  17. 回归分析中的多重共线性问题
  18. 兴趣变高薪副业,知名插画师走尺带你感受插画的魅力
  19. 给定一个成绩a,使用switch结构求出a的等级。A:90-100,B:80-89,C:70-79,D:60-69,E:0~59
  20. 《东周列国志》第五十二回 公子宋尝鼋构逆 陈灵公衵服戏朝

热门文章

  1. SAP Cloud for Customer的employee创建会自动生成Business partner
  2. python不满足条件重新输入_在python里为何不满足while条件,while里语句却可以执行?...
  3. cname 别名记录 解析过程_云解析是什么?需要购买吗?
  4. 为什么剩余数不能相加_行测备考:如何快解数量关系中的剩余定理
  5. 系统接口对接的进度工作应该谁来干_第三方分账系统开发的那些坑,给你节省几十万...
  6. 没有内存条电脑能开机吗_电脑没内存条能开机吗?这位朋友说他的电脑没内存条都用几年了!...
  7. crontab 每分钟一次_Celery实现定时任务crontab
  8. mongodb存list_查询 MongoDB 子文档的 List 字段
  9. mysql优化器分析器_MySQL查询优化器的概念和原理整个执行过程
  10. 移动app部分机型无法唤起h5支付宝支付_谜之wxs,uni-app如何用它大幅提升性能