rxjs入门6之合并数据流
一 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之合并数据流的更多相关文章
- rxjs入门5之创建数据流
一 创建同步数据流 1.creat Observable.create = function (subscribe) { return new Observable(subscribe); }; 2. ...
- Rxjs入门实践-各种排序算法排序过程的可视化展示
Rxjs入门实践-各种排序算法排序过程的可视化展示 这几天学习下<算法>的排序章节,具体见对排序的总结,想着做点东西,能将各种排序算法的排序过程使用Rxjs通过可视化的方式展示出来,正好练 ...
- RxJS入门
一.RxJS是什么? 官方文档使用了一句话总结RxJS: Think of RxJS as Lodash for events.那么Lodash主要解决了什么问题?Lodash主要集成了一系列关于数组 ...
- RxJS 入门指引和初步应用
作者:徐飞链接:https://zhuanlan.zhihu.com/p/25383159来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. RxJS是一个强大的React ...
- ReactiveX 学习笔记(5)合并数据流
Combining Observables 本文的主题为合并 Observable 的操作符. 这里的 Observable 实质上是可观察的数据流. RxJava操作符(四)Combining An ...
- RxJS入门之函数响应式编程
一.函数式编程 1.声明式(Declarativ) 和声明式相对应的编程⽅式叫做命令式编程(ImperativeProgramming),命令式编程也是最常见的⼀种编程⽅式. //命令式编程: fun ...
- rxjs入门指南
使用场景 在复杂的,频繁的异步请求场景,使用rxjs. 在依赖的多个异步数据,决定渲染的情景,使用rxjs. 总之:在前台频繁的.大量的.和后台数据交互的复杂项目里面,使用rxjs(web端,iOS, ...
- rxjs入门3之项目中ajax函数封装
项目中ajax函数封装 ⽹页应⽤主要数据源有两个:⼀个是⽹页中的DOM事件,另⼀个就是通过AJAX获得的服务器资源.我们已经知道fromEvent这个操作符可以根据DOM事件产⽣Observable对 ...
- Hadoop HDFS编程 API入门系列之合并小文件到HDFS(三)
不多说,直接上代码. 代码 package zhouls.bigdata.myWholeHadoop.HDFS.hdfs7; import java.io.IOException;import ja ...
随机推荐
- sql 常用的查询套路
1. 写一个sql:,查询商城每天的用户数及每天累计用户数 date user_count total_count2016-12-01 1 12016- ...
- 分享知识-快乐自己:解决 Maven 无法下载 fastdfs-client-java 依赖。
因为fastdfs-client-java-1.27-SNAPSHOT.jar这个依赖包在maven中央仓库是没有的. 需要自己编译源码成jar本地安装到maven 的本地仓库,安装完以后就能正常引用 ...
- 基于Protobuf的分布式高性能RPC框架——Navi-Pbrpc
基于Protobuf的分布式高性能RPC框架——Navi-Pbrpc 二月 8, 2016 1 简介 Navi-pbrpc框架是一个高性能的远程调用RPC框架,使用netty4技术提供非阻塞.异步.全 ...
- mybatis学习第(二)天
Mybatis第二天 高级映射 查询缓存 关于与spring的整合和反转工程我偷懒了,下次看. 使用的sql: CREATE TABLE USER( id INT PRIMARY KEY A ...
- C++中类型转换
static_cast 静态类型转换. 在编译的时候C++编译器会做类型检查,基本类型能转换,指针类型不进行转换. C语言中隐式类型转换的地方均可以使用static_cast. ...
- Android基于socket的群聊程序
在网上看了好多,但是感觉不是太简单就是只能单独聊,所以就自己写了个可以群聊的,直接上代码了 一.服务器端 这里用的MyEclipse作为服务器端 MyServerScoket.java package ...
- adt-bundle-windows-x86_64-20130522.zip 下载
直接复制这个链接到迅雷下载即可:http://dl.google.com/android/adt/adt-bundle-windows-x86_64-20130522.zip
- OpenCV——径向模糊
参考来源: 学习OpenCV:滤镜系列(5)--径向模糊:缩放&旋转 // define head function #ifndef PS_ALGORITHM_H_INCLUDED #defi ...
- json 文件解析与应用
第一步:首先弄一个 json 文件 我这里成为 config.json 内容如下 { ": { , "desc":"中华人民共和国" }, &qu ...
- bzoj 3232: 圈地游戏 01分数规划
题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=3232 题解: 首先我们看到这道题让我们最优化一个分式. 所以我们应该自然而然地想到01分 ...