5 张弹珠图彻底弄清 RxJS 的拉平策略:mergeMap、switchMap、concatMap、exhaustMap

简介: RxJS 的操作符理解起来确实比较复杂,比如最常用的几种 map 操作符,本篇就来使劲冲一冲它们!!

RxJS 的操作符理解起来确实比较复杂,比如最常用的几种 map 操作符,本篇就来使劲冲一冲它们!!

image.png

  • 原创文章,非商业转载请说名出处


map 操作想必大家一定不陌生:


const { of } = Rx;
const { map  } = 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 呢 ?


const { of } = Rx;
const { map } = 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{ .. }


我们在 rxviz.com/ 的弹珠图中,可以清晰的看到:返回的仍是 observable

image.png


并且 observable 由最初的 1 个,变成了 2 个(圆圈就是 observable),数据仍在里面没有被订阅解析出来。


虽然,我们可以用粗暴的方法,在订阅 .subscribe 里面再次调用订阅 .subscribe ,则可得值:

const { of } = Rx;
const { map } = 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 操作符;


代码如下:


const { of } = Rx;
const { mergeMap} = 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,它们能够提供不同方向的拉平策略。

我们再借助 rxviz.com/ 的弹珠图,一眼便能看到它们的差异:


设置一个定时器,每一秒都发出一个 observable,一共发 3 次,来看下分别得值;


  • mergeMap
const { of,interval} = Rx;
const { mergeMap,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))
)

image.png


mergeMap 会同时维护多个活动的内部订阅;


  • switchMap
const { of,interval} = Rx;
const { switchMap,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))
)
复制代码

image.png


switchMap,在每次发出时,会取消前一个内部 observable 的订阅,然后订阅一个新的 observable;


  • concatMap
const { of,interval} = Rx;
const { concatMap ,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))
)

image.png

concatMap 会在之前前一个内部 observable 完成后,才会订阅下一个;


  • exhaustMap
const { of,interval} = Rx;
const { exhaustMap ,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))
)

image.png

exhaustMap 映射成内部 observable,忽略其他值直到该 observable 完成;


OK,以上便是本篇分享。

觉得不错点个赞吧👍👍👍,您的鼓励,我的动力,坚持输出质量好文~~ 欢迎评论讨论

我是掘金安东尼,输出暴露输入,技术洞见生活。再会吧~~ 👋👋👋


相关文章
|
前端开发
rxjs Observable 设计原理背后的 Pull 和 Push 思路
rxjs Observable 设计原理背后的 Pull 和 Push 思路
|
12月前
|
消息中间件 存储 负载均衡
两个实验让我彻底弄懂了「订阅关系一致」
这篇文章,笔者想聊聊 RocketMQ 最佳实践之一:**保证订阅关系一致**。 订阅关系一致指的是同一个消费者 Group ID 下所有 Consumer 实例所订阅的 Topic 、Tag 必须完全一致。 如果订阅关系不一致,消息消费的逻辑就会混乱,甚至导致消息丢失。
两个实验让我彻底弄懂了「订阅关系一致」
|
5月前
|
存储 Python
[重学Python]Day3 函数和模块的使用
本文介绍了Python中的函数和模块的使用。函数用于避免代码重复,通过`def`定义,参数可有默认值或可变参数。模块管理同名函数,通过`import`导入。示例包括计算最大公约数和最小公倍数、判断回文数和素数的函数,以及检测回文素数的程序。
38 0
|
5月前
|
前端开发 开发者
第二十三章 案例TodoList之数据更新
第二十三章 案例TodoList之数据更新
第二十三章 案例TodoList之数据更新
|
5月前
第二十一章 案例TodoList之新增数据
第二十一章 案例TodoList之新增数据
|
11月前
一文解释mapState的来龙去脉
一文解释mapState的来龙去脉
不适合做朋友的人有哪些逻辑特征(三)
不适合做朋友的人有哪些逻辑特征(三)
84 0
|
自然语言处理 PyTorch 算法框架/工具
离线解耦的文本表征方法(持续更新ing...)
本文仅介绍离线、解耦的、直接对文本进行表征的方法。分成通过词嵌入池化得到句子嵌入,和直接进行句子嵌入两种做法。主要用PyTorch实现。 本文将使用一个数据集来撰写相应代码,并使用简单的线性分类器来实现multi-class文本分类,分类模型的代码(我每个都是跟前面的文本表征部分直接写在同一个脚本里的)和各表征方法的效果在第4节展示。 本文使用的分词方式是jieba默认模式。其他注意事项看具体各分节内容。
离线解耦的文本表征方法(持续更新ing...)
|
前端开发
#yyds干货盘点 【React工作记录六】如何实现一个图片的伪预览效果
#yyds干货盘点 【React工作记录六】如何实现一个图片的伪预览效果
114 0
|
JSON 前端开发 数据格式
#yyds干货盘点 【React工作记录十二】前端对接口参数错误如何解决
#yyds干货盘点 【React工作记录十二】前端对接口参数错误如何解决
165 0