前言

我们一样从简单和常用的入手.

第一篇介绍了 Creation Operators

上一篇介绍了 Filter Operators

这一篇来到 Join Creation Operators.

参考

Docs – Join Creation Operators

merge

merge 会同时 subscribe 所有的 Observable. 任何一个发布都会接收.

const s1 = new Subject();
const s2 = new Subject();
merge(s1, s2).subscribe(v => console.log(v)); // s1..s2
s1.next('s1');
s2.next('s2');

merge 会创建出一个新的 Observable. 当被订阅时, 它会去 subscribe s1 和 s2.

一旦 s1 或 s2 发布, merge observable 也会随之发布. merge 的 subscriber 就会接收.

merge 常用来实现多种不同监听, 但要执行相同逻辑的场景.

比如 click submit button 或 keydown enter 都会执行 ajax search. 那么我们就可以写 merge(click$, enter$).subscrube(() => ajax());

combineLatest

combineLatest 和 merge 类似, 创建新的 Observable 并且订阅所有 Observable

const s1 = new Subject();
const s2 = new Subject();
combineLatest([s1, s2]).subscribe(([v1, v2]) => console.log([v1, v2])); // [s1, s2]
s1.next('s1'); // 不会接收, 因为 s2 还没有值
s2.next('s2'); // 接收, 因为 s1, s2 都有值了

但它和 merge 有 2 个区别

1. merge 每次只接收到 1 个值 (最新发布的那个), 而 combineLatest 会接收到所有 Observable 的值 (它是一个 Array, 因为每一次发布值都会被 cache 起来)

2. combineLatest 必须等到所有的 Observable 最少发布一次以后, 才会开始接收.

上面的例子中, s1.next('s1') 的时候, console 没有响, 因为 s2 这时还没有任何发布记入. 只有当 s2.next 以后, s1, s2 都有了发布记入, console 才响, 同时获取到了 s1, s2 的最新的值.

combineLatest 在开发中也是经常需要使用到的, 尤其是当我们要 merge 的效果, 同时希望它返回当前所有 Observable 最新值的时候.

以前遇过的坑

const s1 = new Subject();
combineLatest([s1, s1]).subscribe(v => console.log(v));
s1.next('value'); // [value, value]
s1.next('value2'); // [value2, value]..[value2, value2]

效果

虽然都是 s1, 但 combineLatest 会把它们当作不同的 Observable, 会有 2 个订阅, 而 s1.next 就想等于 2 个 Obserable 都发布了值, 但依然是有顺序的哦, 一前一后.

所以会出现 3 个 console. 第二个 console 的接收值是 ['value2', 'value'] 因为第一个 Observable 发布, 第二个用的是 cached value.

zip

zip 和 combineLatest 有点像, 它们都会接收到所有 Observable 最新的值. 只是接收的时机不一样.

多个 Observable 发布的次数往往是没有规律的. 可能 o1 发布了 5 次, o2 才 2 次.

combineLatest 它不管大家的次数, 只要任何一个 Observable 发布, 那就把其它所有的值拉出来, 一起发布出去.

zip 则讲究次数, 只有当每一个 Observable 都达到相同次数, 它才会把每一个 Observable 那一次数的值取出来, 一起发布出去.

看下面这个例子

  const s1 = new Subject();
const s2 = new Subject();
combineLatest([s1, s2]).subscribe(v => console.log(v));
s1.next('s1');
s2.next('s2'); // [s1, s2]
s1.next('s11'); // [s11, s2]
s1.next('s12'); // [s12, s2]
s1.next('s13'); // [s13, s2]
s2.next('s21'); // [s13, s21] zip([s1, s2]).subscribe(v => console.log(v));
s1.next('s1');
s2.next('s2'); // [s1, s2]
s1.next('s11');
s1.next('s12');
s1.next('s13');
s2.next('s21'); // [s11, s21]

zip 最终 console 只响了 2 次. 而 combineLatest 响了 5 次.

虽然 s1 发布了 5 次, 但 zip 要求所有 Observable 必须要有相同次数, 而 s2 只有 2 次, 所以最终只能发布 2 次而已. 而第二次的发布, s1 的 value 并不是它最新的 value 而是它第 2 次发布的 value 哦.

concat

concat 和 merge 类似, 它会 subscribe 所有 Observable 但它不像 merge 那样一开始就全部 subscribe. 它会挨个挨个去 subscribe. 当第一个 Observable complete 以后才去 subscribe 第二个.

const s1 = new Subject();
const s2 = new Subject();
concat(s1, s2).subscribe(v => console.log(v));
s1.next('s1'); // 接收 s1
s2.next('s2'); // 没接收, 因为 s1 还没有 complete, s2 还没有开始 subscribe
s1.complete();
s2.next('s2'); // 接收 s2

forkJoin

forkJoin 好比 Promise.all, 当所有的 Observable complete 后, 它才会接收, 并且得到所有 Observable 最终的值.

const s1 = new Subject();
const s2 = new Subject();
forkJoin([s1, s2]).subscribe(v => console.log(v)); // [s1, s2]
s1.next('s1');
s2.next('s2');
s1.complete();
s2.complete(); // 这时才开始接收

race

race 就是比赛, 第一个发布的 Observable 将保留订阅, 其余的就淘汰退订

const s1 = new Subject();
const s2 = new Subject();
race([s1, s2]).subscribe(v => console.log(v)); // s2..s21
s2.next('s2'); // 接收
s1.next('s1'); // 不接收, 因为 s2 胜出, s1 已经被退订了
s2.next('s21'); // 接收 只有胜出的 s2 发布才会被接收

partition

partition 的作用是把 1 个 Observable 拆分成 2 个.

上一篇介绍 filter operator 时, 有写过下面这个 odd, even 例子

const source = from([1, 2, 3, 4]);
const odd$ = source.pipe(filter(v => v % 2 !== 0));
const even$ = source.pipe(filter(v => v % 2 === 0));
odd$.subscribe(v => console.log(v)); // 1..3
even$.subscribe(v => console.log(v)); // 2..4

它可以用 partition 改写成

const [odd$, even$] = partition(source, v => v % 2 !== 0);

条件 true 表示它属于第一个 Observable, false 则进入第二个 Observable.

注: source 没有 share 的概念哦,odd$ even$ 是两个独立的 stream。

一句话总结

merge : 任何一个发布, 接收最新发布值

combineLatest : 任何一个发布, 接收所有最新的值 (开始接收条件: 所有 Observable 最少要有一次发布)

zip : 和 combineLatest 一样, 但它 care Observable 发布的次数. 当所有 Observable 都满足 n 次的时候发布, 接收第 n 次所有的值.

concat : 上一个 Observable complete 了才 subscribe 下一个

forkJoin: Promise.all, 所有 Observable complete 后, 接收所有最终的值

race : 第一个发布的 Observable 继续订阅, 退订其余的 Observale

partition : 通过 if else 把一个 Observable 拆分成 2 个

RxJS 系列 – Join Creation Operators的更多相关文章

  1. RxSwift 系列(三) -- Combination Operators

    RxSwift 系列(三) -- Combination Operators 前言 本篇文章将要学习如何将多个Observables组合成一个Observable. Combination Opera ...

  2. [RxJS] Creation operators: interval and timer

    It is quite common to need an Observable that ticks periodically, for instance every second or every ...

  3. [RxJS] Creation operators: empty, never, throw

    This lesson introduces operators empty(), never(), and throw(), which despite being plain and void o ...

  4. [RxJS] Creation operators: fromEventPattern, fromEvent

    Besides converting arrays and promises to Observables, we can also convert other structures to Obser ...

  5. [RxJS] Creation operators: from, fromArray, fromPromise

    The of() operator essentially converted a list of arguments to an Observable. Since arrays are often ...

  6. Apache Flink 漫谈系列 - JOIN 算子

    聊什么 在<Apache Flink 漫谈系列 - SQL概览>中我们介绍了JOIN算子的语义和基本的使用方式,介绍过程中大家发现Apache Flink在语法语义上是遵循ANSI-SQL ...

  7. RxSwift 系列(四) -- Transforming Operators

    前言 本篇文章将要学习RxSwift中四种转换操作符: map flatMap flatMapLatest scan map 通过使用一个闭包函数将原来的Observable序列转换为一个新的Obse ...

  8. RxSwift 系列(七) -- Connectable Operators

    前言 本篇文章将要学习RxSwift中连接操作符. Connectable Observable在订阅时不发射事件消息,而是仅当调用它们的connect()方法时才发射消息,这样就可以等待所有我们想要 ...

  9. rxjs笔记(未完成)

    首先是 Observable 和promise的区别, 1返回值个数,Observable 可以返回0到无数个值. 2.Promise主动推送,控制着"值"何时被 "推送 ...

  10. RxJS——Operators

    RxJS 的操作符(operators)是最有用的,尽管 Observable 是最基本的.操作符最基本的部分(pieces)就是以申明的方式允许复杂的异步代码组合简化. 什么是操作符? 操作符是函数 ...

随机推荐

  1. Solo开发者社区-H5-Dooring, 开箱即用的零代码搭建平台

    Dooring-Saas 是一款功能强大,高可扩展的零代码解决方案,致力于提供一套简单方便.专业可靠.无限可能的页面可视化搭建最佳实践.(Solo社区 投稿) 功能特点 可扩展, Dooring 实现 ...

  2. 在MoneyPrinterPlus中使用本地chatTTS语音模型

    之前MoneyPrinterPlus在批量混剪,一键AI生成视频这些功能上的语音合成功能都用的是云厂商的语音服务,比阿里云,腾讯云和微软云. 云厂商虽然提供了优质的语音服务,但是用起来还是要收费. 为 ...

  3. 可视化—AntV G6实现节点连线及展开收缩分组

    AntV 是蚂蚁金服全新一代数据可视化解决方案,主要包含数据驱动的高交互可视化图形语法G2,专注解决流程与关系分析的图表库 G6.适于对性能.体积.扩展性要求严苛的场景. demo使用数字模拟真实的节 ...

  4. [oeasy]python0141_自制模块_module_reusability_复用性

    自制包内容 回忆上次内容 上次导入了外部的py文件 import my_module 导入一个自己定义的模块   可以使用my_module中的变量 不能 直接使用 my_module.py文件中的变 ...

  5. oeasy教您玩转linux010206toilet

    我们来回顾一下 上一部分我们都讲了什么? 用apt查询并下载了figlet 玩了一下字符画 设置了字符画的字体 但是没有修改颜色 这次我们来找找另一个命令toilet apt search toile ...

  6. iOS开发基础133-崩溃预防

    现代移动应用的用户体验依赖于其稳定性和可靠性.然而,在开发过程中,我们时常会遇到各种崩溃问题.崩溃不仅会影响用户的使用体验,还可能损害应用的声誉.因此,本文将详细介绍一个名为CrashPreventi ...

  7. 【Git】GithubDesktop 忽略文件无法忽略BUG

    问题描述: 从仓库拉取的[.gitignore]忽略配置文件,在项目跑起来之后会生成诸多.idea文件,target打包文件 一开始没有忽略,但是发现使用GD配置之后忽略无效: 解决办法: 做一次随便 ...

  8. IEEE TCDS 专刊"Embodied AI in Indoor Robotics"征稿通知

    原文地址: https://mp.weixin.qq.com/s/Z-U4EO6FCF703yMwHXAq5A 随着深度学习和强化学习在机器人学领域的迅猛发展,尤其是大型语言模型的创新进步,具身人工智 ...

  9. Linux中scanf类型匹配错误,特指scanf("%d", &c ) ,导致死循环的解决方法 —— fflush(stdin)和getchar()的使用

    如题,朋友领导的孩子大学作业是个C语言编写的管理信息系统发来要我给改改,原代码的配置环境是Windows的C环境,由于10多年没有搞过Windows下的C语言了于是换上了Ubuntu18.04的系统上 ...

  10. C# 遇见System.Net.Http不兼容的解决方案

    背景 假设我有一个项目A,调用B项目里面的HttpClient.A里面的System.Net.Http引用路径为(版本4.0.0.0) C:\Program Files (x86)\Reference ...