一 concat,merge,zip,combineLatest等合并类操作符

以上操作符在版本6中已经只存在静态方法,不能在pipe中使用。

import {concat,merge,zip,combineLatest}
1.concat (obs1,obs2,obs3) 首尾相连

依次将多个observable首尾合并,必须在第一个obs1的数据全部完成,才能进行第二个obs2,如果第一个为interval(1000),那么obs2 和obs3 也就永远没有机会得到输出。

concat(of(1,2,3),interval).subscribe(console.log);
// 1 2 3 0 1 2 3 ...
2.merge 先到先得快速通过

merge会第⼀时间订阅所有的上游Observable,然后对上游的数据采取“先到先得”的策略,任何⼀个Observable只要有数据推下来,就⽴刻转给下游Observable对象。

merge(interval(1000),of(1,2,3)).subscribe(console.log);
merge(of(1,2,3),interval(1000)).subscribe(console.log);
//两种情况的输出结果一样,都是先一次性输出1 2 3 再间隔一秒依次输出0 1 2 ...
const source1$ = Observable.timer(0, 1000).map(x => x+'A');
const source2$ = Observable.timer(500, 1000).map(x => x+'B');
merge(source1$, source2$).subscribe(
console.log,
null,
() => console.log('complete')
);
//0A
//0B
//1A
//1B
//2A
//2B

merge 的应用场景:我们知道fromEvent可以从⽹页中获取事件,只可惜,fromEvent⼀次只能从⼀个DOM元素获取⼀种类型的事件。⽐如,我们关⼼某个元素的click事件,同时也关⼼这个元素上的touchend事件,因为在移动设备上touchend事件出现得⽐click更早,这两个事件的处理是⼀模⼀样的,但是fromEvent不能同时获得两个事件的数据流,这时候就要借助merge的⼒量了,代码如下:

const click$ = Rx.Observable.fromEvent(element, 'click');
const touchend$ = Rx.Observable.fromEvent(element, 'touchend');
merge(click$, touchend$).subscribe(eventHandler)
3.zip :拉链式组合

一对一的合并

  • zip会把上游的数据转化为数组形式,每⼀个上游Observable贡献的数据会在对应数组中占⼀席之地.
  • 默认的输出格式为数组格式,可通过第二个参数进行参数格式组装
  • 简而言之:不管是同步产生数据还是异步产生的数据,都会每次依次从需要合并的observable中取一个数据合并成一个数组输出,当某一个observer不再吐出数据了,则终止合并,执行complete函数
const source1$ = Observable.of(1, 2, 3);
const source2$ = Observable.of('a', 'b', 'c');
zip(source1$, source2$).subscribe(
console.log,
null,
() => console.log('complete')
);
//[ 1, 'a' ]
//[ 2, 'b' ]
//[ 3, 'c' ]
//complete

4.combineLatest:合并最后一个数据
  • 输出的数组中元素个数与合并的observable的个数相等。
  • 在合并的observable中,只有最后一个元素为下游,前面的参数如果有同步的数据,同步数据中只有最后一个数据能进入数据流
  • 默认的输出格式为数组格式,可通过第二个参数进行参数格式组装
  • 第一次执行,当上游产生了数据,下游还没来得及产生数据时,就会等待。第二轮时候,不管是上游或者下游产生一个数据,都会执行输出,还没来得及产生数据的observable就输出原来产生的数据,如下弹珠图
const source1$ = Observable.timer(500, 1000);
const source2$ = Observable.timer(1000, 1000);
combineLatest(source1$,source2$).subscribe(
console.log,
null,
() => console.log('complete')
);
//[ 0, 0 ]
//[ 1, 0 ]
//[ 1, 1 ]
//[ 2, 1 ]
//[ 2, 2 ]
//[ 3, 2 ]

5.withLatestFrom
  • withLatestFrom 为管道中使用的方法。默认的输出格式为数组格式,可通过第二个参数进行参数格式组装
  • withLatestFrom只有实例操作符的形式,⽽且所有输⼊Observable的地位并不相同,调⽤withLatestFrom的那个Observable对象起到主导数据产⽣节奏的作⽤,作为参数的Observable对象只能贡献数据,不能控制产⽣数据的时机。
const source1$ = Observable.timer(0, 2000).map(x => 100 * x);
const source2$ = Observable.timer(500, 1000);
source1$.pipe(
withLatestFrom(source2$, (a,b)=> a+b);
).subscribe(
console.log,
null,
() => console.log('complete')
);



source1$产⽣第⼀个数据0时,withLatestFrom的另⼀个输⼊Observable对象source2$还没有产⽣数据,所以这个0也被忽略了。

解决glitch

例1:

const original$ = Observable.timer(0, 1000);
const source1$ = original$.map(x => x+'a');
const source2$ = original$.map(x => x+'b');
const result$ = source1$.pipe(withLatestFrom(source2$);)
result$.subscribe(
console.log,
null,
() => console.log('complete')
);

例2:

const event$ = Rx.Observable.fromEvent(document.body, 'click');
const x$ = event$.map(e => e.x);
const y$ = event$.map(e => e.y);
const result$ = x$.pipe(combineLatest(y$, (x, y) => `x: ${x}, y: ${y}`)).subscribe(
(location) => {
console.log('#render', location);
document.querySelector('#text').innerText = location;
}
);
race :胜者通吃

race就是“竞争”,多个Observable对象在⼀起,看谁最先产⽣数据,不过这种竞争是⼗分残酷的,胜者通吃,败者则失去所有机会。

简而言之,通过race合并多个observable时,最先吐出数据那个observable会成为数据源,其它的observable会被淘汰。

startWith

startWith只有实例操作符的形式,其功能是让⼀个Observable对象在被订阅的时候,总是先吐出指定的若⼲个数据。下⾯是使⽤startWith的⽰例代码

of(0,1,2).pipe(startWith('a','b')).subscribe(console.log);
//先依次吐出 a b 0 1 2
forkJoin
  • forkJoin可以接受多个Observable对象作为参数,forkJoin产⽣的Observable对象也很有特点,它只会产⽣⼀个数据,因为它会等待所有参数Observable对象的最后⼀个数据,也就是说,只有当所有Observable对象都完结,确定不会有新的数据产⽣的时候,forkJoin就会把所有输⼊Observable对象产⽣的最后⼀个数据合并成给下游唯⼀的数据。
  • forkJoin就是RxJS界的Promise.all,Promise.all等待所有输⼊的Promise对象成功之后把结果合并,forkJoin等待所有输⼊的Observable对象完结之后把最后⼀个数据合并。
  • 返回数组形式,数组中元素个数为合并的observable的个数
forkJoin(interval(1000).pipe(take(3)),of(1,2,3),timer(2000,1000).pipe(take(3))).subscribe(console.log);
// [2,3,2]
```js ### 高阶Observable
简言之:⾼阶函数就是产⽣函数的函数;类似,所谓⾼阶Observable,指的是产⽣的数据依然是Observable的Observable
##### 1.concatAll
concatAll只有⼀个上游Observable对象,这个Observable对象预期是⼀个⾼阶Observable对象,concatAll会对其中的内部Observable对象做concat的操作.
```js
interval(1000).pipe(
take(2),
map(x=>interval(1500).pipe(take(2),map(x=> `${x}:x,y:${y}`))),
concatAll()
).subscribe(console.log);
// 0:a,b:0
// 0:a,b:1
// 1:a,b:0
// 1:a,b:1

concat 实际运用

fromEvent(document.body,'mousedown').pipe(
map(
e=>fromEvent(document.body,'mousemove').pipe(map(e=>{return {x:e.clientX,y:e.clientY}}), takeUntil(fromEvent(document.body,'mouseup')))
),
concatAll()
).subscribe(console.log);
mergeAll

mergeAll就是处理⾼阶Observable的merge,只是所有的输⼊Observable来⾃于上游产⽣的内部Observable对象.

interval(1000).pipe(
take(2),
map(x => Observable.interval(1500).map(y => x+':'+y).take(2)),
mergeAll()
)



mergeAll只要

发现上游产⽣⼀个内部Observable就会⽴刻订阅,并从中抽取收据,所以在上图中,第⼆个内部Observable产⽣的数据1:0会出现在第⼀个内部Observable产⽣的数据0:1之前.

zipAll
interval(1000).pipe(
take(2),
map(x => Observable.interval(1500).map(y => x+':'+y).take(2)),
zipAll()
)
//[ '0:0', '1:0' ]
//[ '0:1', '1:1' ]
//complete
combineAll

combineAll就是处理⾼阶Observable的combineLatest,可能是因为combine-LatestAll太长了,所以RxJS选择了combineAll这个名字。

interval(1000).pipe(
take(2),
map(x => Observable.interval(1500).map(y => x+':'+y).take(2)),
combeneAll()
)
//[ '0:0', '1:0' ]
//[ '0:1', '1:0' ]
//[ '0:1', '1:1' ]
//complete
switchAll
  • switch的含义就是“切换”,总是切换到最新的内部Observable对象获取数据。每当switch的上游⾼阶Observable产⽣⼀个内部Observable对象,switch都会⽴刻订阅最新的内部Observable对象上,如果已经订阅了之前的内部Observable对象,就会退订那个过时的内部Observable对象,这个“⽤上新的,舍弃旧的”动作,就是切换。
  • 应用场景:也就是外层的数据产生快于内层的数据产生的速度造成数据积压,需求又能够舍弃原来的旧的外层的数据不让其旧的外层数据再传递到内层产生数据了。

    简而言之,当外层新产生数据时,无论内部数据产生情况如何都作废,重新计算数据流
interval(1000).pipe(
take(3),
map(x => Observable.interval(1500).map(y => x+':'+y).take(2)),
switchAll()
)
//1:0
//1:1
//complete



第⼀个Observable对象有机会产⽣数据0:0,但是在第⼆个数据0:1产⽣之前,第⼆个内部Observable对象产⽣,这时发⽣切换,第⼀个内部Observable就退场了。同样,第⼆个内部Observable只有机会产⽣⼀个数据1:0,然后第三个内部Observable对象产⽣,之后没有新的内部Observable对象产⽣,所以第三个Observable对象的两个数据2:0和2:1都进⼊了下游。

exhaust
  • 在耗尽当前内部Observable的数据之前不会切换到下⼀个内部Observable对象
  • 同样是连接⾼阶Observable产⽣的内部Observable对象,但是exhaust的策略和switch相反,当内部Observable对象在时间上发⽣重叠时,情景就是前⼀个内部Observable还没有完结,⽽新的Observable又已经产⽣,到底应该选择哪⼀个作为数据源?switch选择新产⽣的内部Observable对象,exhaust则选择前⼀个内部Observable对象.
interval(1000).pipe(
take(3),
map(x => Observable.interval(700).map(y => x+':'+y).take(2)),
exhaust()
)

rxjs入门6之合并数据流的更多相关文章

  1. rxjs入门5之创建数据流

    一 创建同步数据流 1.creat Observable.create = function (subscribe) { return new Observable(subscribe); }; 2. ...

  2. Rxjs入门实践-各种排序算法排序过程的可视化展示

    Rxjs入门实践-各种排序算法排序过程的可视化展示 这几天学习下<算法>的排序章节,具体见对排序的总结,想着做点东西,能将各种排序算法的排序过程使用Rxjs通过可视化的方式展示出来,正好练 ...

  3. RxJS入门

    一.RxJS是什么? 官方文档使用了一句话总结RxJS: Think of RxJS as Lodash for events.那么Lodash主要解决了什么问题?Lodash主要集成了一系列关于数组 ...

  4. RxJS 入门指引和初步应用

    作者:徐飞链接:https://zhuanlan.zhihu.com/p/25383159来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. RxJS是一个强大的React ...

  5. ReactiveX 学习笔记(5)合并数据流

    Combining Observables 本文的主题为合并 Observable 的操作符. 这里的 Observable 实质上是可观察的数据流. RxJava操作符(四)Combining An ...

  6. RxJS入门之函数响应式编程

    一.函数式编程 1.声明式(Declarativ) 和声明式相对应的编程⽅式叫做命令式编程(ImperativeProgramming),命令式编程也是最常见的⼀种编程⽅式. //命令式编程: fun ...

  7. rxjs入门指南

    使用场景 在复杂的,频繁的异步请求场景,使用rxjs. 在依赖的多个异步数据,决定渲染的情景,使用rxjs. 总之:在前台频繁的.大量的.和后台数据交互的复杂项目里面,使用rxjs(web端,iOS, ...

  8. rxjs入门3之项目中ajax函数封装

    项目中ajax函数封装 ⽹页应⽤主要数据源有两个:⼀个是⽹页中的DOM事件,另⼀个就是通过AJAX获得的服务器资源.我们已经知道fromEvent这个操作符可以根据DOM事件产⽣Observable对 ...

  9. Hadoop HDFS编程 API入门系列之合并小文件到HDFS(三)

    不多说,直接上代码.  代码 package zhouls.bigdata.myWholeHadoop.HDFS.hdfs7; import java.io.IOException;import ja ...

随机推荐

  1. eclipse快捷提示原理

    eclipse快捷提示利用的是java反射,因为只有反射才能让eclipse知道类有哪些变量和方法.

  2. java:Eclipse:Could not create the view:解决办法

    Eclipse:Could not create the view: Plug-in org.eclipse.jdt.ui was unable to load class org.eclipse.j ...

  3. java:Map借口及其子类HashMap四

    java:Map借口及其子类HashMap四 使用非系统对象作为key,使用匿名对象获取数据 在Map中可以使用匿名对象找到一个key对应的value. person: public class Ha ...

  4. artDialog 简单使用!

    简介 artDialog是一个轻巧且高度兼容的javascript对话框组件,可让你的网页交互拥有桌面软件般的用户体验. 功能: 支持锁定屏幕(遮罩).模拟alert和confirm.多窗口弹出.静止 ...

  5. 尴尬,qt出现错误,然后莫名又好了..

    Starting D:\code\qt\myChess\day01\build-HelloQT-Desktop_Qt_5_5_0_MinGW_32bit-Debug\debug\HelloQT.exe ...

  6. java_面试_01_一个月的面试总结(java)

    重点知识 由于我面试的JAVA开发工程师,针对于JAVA,需要理解的重点内容有: JVM内存管理机制和垃圾回收机制(基本每次面试都会问,一定要搞得透彻) JVM内存调优(了解是怎么回事,一般做项目过程 ...

  7. codeforces 637D D. Running with Obstacles(dp,水题,贪心)

    题目链接: D. Running with Obstacles time limit per test 2 seconds memory limit per test 256 megabytes in ...

  8. 七牛 python

    Python SDK使用指南 上传策略 变量 对象存储 API 参考手册 多媒体数据处理 API 参考手册

  9. ffmpeg用法(心得体会还有你见过的用法)

    ffmpeg的常用用法很多,我这里提供的用法有可能有许多地方是你没见过的. 一.ffmpeg合并视频 我经常需要切割再把一些零碎的视频给拼接起来,这样可以省许多磁盘空间.其实用mencoder挺不错的 ...

  10. iOS获取设备型号的方法

    1. [UIDevice currentDevice].model   自己写的看只抓到模拟器和iPhone.暂时不推荐. 2.自己写的找的方法再添加.直接  NSString * deviceMod ...