rxjs合并数据流操作符
一、concat首尾相连
工作方式:
当第一个Observable对象complete之后,concat就会去subscribe第二个Observable对象获取数据,把同样的数据传给下游。
直到最后一个Observable完结之后,concat产生的Observable也就完结了。
import { of,concat } from 'rxjs'; ... const source1$ = of(1,2,3) const source2$ = of(4,5,6) const source$ = concat(source1$,source2$) source$.subscribe( console.log, null, ()=>console.log('complete') ) ...
输出结果
二、merge:先到先得快速通过
工作方式:
第一个Observable对象不完结,并不影响下游的observable对象,随先得到,就先输出。
当所有的Observable对象完结了,merge才会完结自己的Observable对象。
import { timer, merge } from 'rxjs'; import 'rxjs/add/operator/map' ... // 从第0毫秒开始,每隔1000毫秒产生一个数据,依次是:0A、1A、2A.... const source1$ = timer(0,1000).map( x=> x + 'A')
// 从第500毫秒开始,每隔1000毫秒产生一个数据,依次是:0B、1B、2B... const source2$ = timer(500,1000).map( x=> x+'B') const source$ = merge(source1$,source2$) source$.subscribe( console.log, null, ()=>console.log('complete') ) ...
输出结果前几个数值如下:
同步限流
merge有一个可选参数,放在最后。表示指定可以同时合并的observable对象个数。
如果前面两个observable对象没有完结,第三个Observable对象永远不会进入source$。
const source1$ = timer(0,1000).map( x=> x + 'A') const source2$ = timer(500,1000).map( x=> x+'B') const source3$ = timer(1000,1000).map( x=> x+'C') const source$ = merge(source1$,source2$,source3$,2)
merge的应用场景
fromEvent可以从网页中获取事件,但是fromEVent一次只能从一个DOM元素获取一种类型的事件。
如果某个元素的click事件,也同时需要touchend事件,因为移动设备上touchend事件出现得比click更早。
这两个事件的处理是一模一样的。
此时需要借助merge的力量。
const source1$ = fromEvent(document.querySelector('#text'),'click') const source2$ = fromEvent(document.querySelector('#text'),'touchend') const source$ = merge(source1$,source2$)
结论:
merge只对产生异步数据的Observable才有意义。
三、zip:拉链式组合
工作方式:
一对一合并,如果source1$吐出数据更快,也会等着source2$数据吐出后一对一配对输出。
即使source1$还有多余的数据,如果没有配对数据,将会执行complete完结。
因此会造成数据挤压问题。
zip也可以多个数据流合并。
const source1$ = of(1,2,3,4,5) const source2$ = of('a','b','c') const source$ = zip(source1$,source2$)
输出结果:
四、combineLatest合并最后一个数据
实例1:
import { timer, combineLatest } from 'rxjs'; // 从第500毫秒开始,每隔1000毫秒产生数据 const source1$ = timer(500,1000)
// 从第1000毫秒开始,每隔1000毫秒产生数据 const source2$ = timer(1000,1000) const combineLatest$ = combineLatest(source1$,source2$)
输出结果:(前几个结果)
弹珠图:
实例2:
const source1$ = timer(500,1000) const source2$ = of('a') const combineLatest$ = combineLatest(source1$,source2$)
执行结果:(前几个结果)
实例3:
const source1$ = of('a','b','c') const source2$ = of(1,2,3) const combineLatest$ = combineLatest(source1$,source2$)
执行结果:
解析:
实例4:
const source1$ = of('a','b','c') const source2$ = of(1,2,3) const source3$ = of('x','y') const combineLatest$ = combineLatest(source1$,source2$,source3$)
执行结果:
实例5:定制下游数据
zip和combineLatest一样默认输出的数据时数组形式,因此zip也和combineLatest一样默认输出的数据时数组形式,
同样也可以利用最后一个函数参数来定制输出数据的形式。
const source1$ = timer(500,1000) const source2$ = timer(1000,1000) const project = (a,b) => `${a} and ${b}` const combineLatest$ = combineLatest(source1$,source2$,project)
执行结果:
五、withLatestFrom
工作方式:
withLatestFrom产生数据,只是更新两者的最新数据,
如果两者其中一个不是最新数据,也不会产生新的数据。
实例1:
import { timer } from 'rxjs'; import 'rxjs/add/operator/map' import 'rxjs/add/operator/withLatestFrom' const source1$ = timer(0,2000).map( x=> 100 * x ) const source2$ = timer(500,1000) const project = (a,b) => a + b const combineLatest$ = source1$.withLatestFrom(source2$,project)
执行结果:(前几个)
弹珠图如下所示:
六、解决glitch问题
实例1:
import { timer } from 'rxjs'; import 'rxjs/add/operator/map' import 'rxjs/add/operator/withLatestFrom' const original$ = timer(0,1000) const source1$ = original$.map( x=> x+'a') const source2$ = original$.map( x=> x+'b') const combineLatest$ = source1$.withLatestFrom(source2$)
执行结果:(前几个)
实例2:
import { combineLatest, fromEvent } from 'rxjs'; import 'rxjs/add/operator/map' const event$ = fromEvent(document.body,'click'); const x$ = event$.map(e => e.x); const y$ = event$.map(e => e.y); const project = (x,y) => `x:${x},y:${y}`; const result$ = combineLatest(x$,y$,project); result$.subscribe( (location) => { console.log('#render', location) document.querySelector('#text').innerHTML = location; } )
当点击三次会出现以下结果:
但是如果用withLatestFrom就可以解决以上问题:
减少不必要的网页渲染。
const result$ = x$.withLatestFrom(x$,y$,project);
当点击三次出现以下结果:
七、race:胜者通吃
谁先吐出第一个数据为胜者,合并产生的数据就是胜者吐出的数据。
import { race, timer } from 'rxjs'; import 'rxjs/add/operator/map' const source1$ = timer(0,2000).map(e => e + 'a'); const source2$ = timer(500,1000).map(e => e + 'b'); const result$ = race(source1$,source2$) result$.subscribe( console.log, null, ()=>console.log('complete') )
执行结果:
弹珠图
八、startWith:先吐出指定的若干个数据
实例1:
import { timer } from 'rxjs'; import 'rxjs/add/operator/startWith' const orginal$ = timer(0,1000) const result$ = orginal$.startWith('start')
执行结果:
实例2:
同样的效果,可以用concat来实现
const orginal$ = timer(0,1000)
const result$ = concat(of('start'),orginal$)
差异:
startWith的一点不足时所有参数都是同步吐出的,如果需要异步吐出参数,那还是只能利用concat。
九、forkJoin:合并所有参数Observable对象的最后一个数据
实例:
import { interval, forkJoin } from 'rxjs'; import 'rxjs/add/operator/map' import 'rxjs/add/operator/take' const source1$ = interval(1000).map( x=> x+'a' ).take(1); const source2$ = interval(1000).map( x => x +'b').take(3); const concated$ = forkJoin(source1$,source2$)
执行结果: