5 张弹珠图彻底弄清 RxJS 的拉平策略(mergeMapswitchMapconcatMapexhaustMap)

实践是知识的母亲,知识是生活的明灯。这篇文章主要讲述5 张弹珠图彻底弄清 RxJS 的拉平策略:mergeMapswitchMapconcatMapexhaustMap相关的知识,希望能为你提供帮助。
map 操作想必大家一定不陌生:

constof= Rx;
constmap= RxOperators;

const namesObservable = of(A, B);
namesObservable.pipe(
map(name => `map $name`)
)

namesObservable .subscribe(result => console.log(`$result`))

// map A
// map B

很直观,因为 map 映射的是“值”,所以足够简单~
但是,如果说,map 映射的是 observable 呢 ?
constof= Rx;
constmap= RxOperators;

const namesObservable = of(A, B);

const http =(name)=>
return of(`$name 1`,`$name 2`);


namesObservable.pipe(
map(name => http(name))
)

namesObservable.subscribe(result => console.log(`$result`))

// 则会得到两个 observable 对象
// ****observable ..
// observable ..

结果发现,最终得到的仍是 observable;在 ??https://rxviz.com/?? 的弹珠图中,可以看到:

observable 由最初的 1 个,变成了 2 个(圆圈就是 observable),数据仍在里面没有被订阅解析出来。
虽然,我们可以用粗暴的方法,在订阅 ??.subscribe??? 里面再次调用订阅 ??.subscribe?? ,则可以得值:
constof= Rx;
constmap= RxOperators;

const namesObservable = of(A, B);

const http =(name)=>
return of(`$name 1`,`$name 2`);


namesObservable.pipe(
map(name => http(name))
)

namesObservable .subscribe(resultObservable =>
resultObservable.subscribe(result => console.log(`$result`) )
)

// A1
// A2
// B1
// B2

但是,这样包裹写法注定是不优雅的,所以,为了解决这个差异,RxJS 引入了 —— Flattening(扁平化)策略!!
我们可以借助 ?flatMap? 操作符,则能得到同样的解析值的效果~ flatMap 其实也就是我们熟知的 ?mergeMap? 操作符;
代码如下:
constof= Rx;
constmergeMap = RxOperators;

const namesObservable = of(A, B);

const http =(name)=>
return of(`$name 1`,`$name 2`);


namesObservable.pipe(
mergeMap(name => http(name))
)

namesObservable.subscribe(result => console.log(`$result`))
// A1
// A2
// B1
// B2

更进一步,沿着这种偏平化策略思路,除了 mergeMap,RxJS 又引入了 switchMap、concatMap 和 exhaustMap,它们能够提供不同种类的拉平策略。
我们借助 ??https://rxviz.com/?? 的弹珠图,一眼便能看到它们的差异:
我们设置一个定时器,每一秒都发出一个 observable,一共发 3 次,来看下分别得值;
  • ?mergeMap?
constof,interval = Rx;
constmergeMap,take,map= RxOperators;

const namesObservable = of(A, B);

const http =(name)=>
return interval(1000)
.pipe(
take(3),
map(()=> of(`$name 1`,`$name 2`))
)


namesObservable.pipe(
mergeMap(name => http(name))
)


  • ?switchMap?
constof,interval = Rx;
constswitchMap,take,map= RxOperators;

const namesObservable = of(A, B);

const http =(name)=>
return interval(1000)
.pipe(
take(3),
map(()=> of(`$name 1`,`$name 2`))
)


namesObservable.pipe(
switchMap(name => http(name))
)


  • ?concatMap?
constof,interval = Rx;
constconcatMap ,take,map= RxOperators;

const namesObservable = of(A, B);

const http =(name)=>
return interval(1000)
.pipe(
take(3),
map(()=> of(`$name 1`,`$name 2`))
)


namesObservable.pipe(
concatMap (name => http(name))
)


  • ?exhaustMap?
constof,interval = Rx;
constexhaustMap ,take,map= RxOperators;

const namesObservable = of(A, B);

const http =(name)=>
return interval(1000)
.pipe(
take(3),
map(()=> of(`$name 1`,`$name 2`))
)


namesObservable.pipe(
exhaustMap (name => http(name))
)

【5 张弹珠图彻底弄清 RxJS 的拉平策略(mergeMapswitchMapconcatMapexhaustMap)】

    推荐阅读