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,以上便是本篇分享。

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

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


相关文章
yum install、localinstall和groupinstall区别
yum install、localinstall和groupinstall区别
967 0
|
XML Java API
SpringBoot 整合 Minio
本文介绍了如何在服务器上安装并配置Minio服务,包括Minio的依赖、配置类以及基本操作。首先,通过Maven添加Minio依赖;接着,在`yml`文件中配置Minio的连接信息;然后,创建`MinIoClientConfig`类将MinioClient注入到Spring容器中;最后,定义`OSSFileService`接口及其实现类`OssFileServiceImpl`,实现文件上传、获取文件URL、临时访问URL和删除文件等操作。
593 2
|
前端开发
前端基础(八)_盒子模型(标准盒子模型和怪异盒子模型)
本文介绍了CSS盒子模型的基本概念,包括内容、内边距、边框和外边距的属性,以及标准盒子模型和怪异盒子模型的区别和转换方法。
1205 1
前端基础(八)_盒子模型(标准盒子模型和怪异盒子模型)
【HarmonyOS Next】状态管理V2版本使用详解
现阶段状态管理V2版本还在试用阶段,但是切实解决了很多在项目中使用V1导致的痛点问题,比如: * 同一数据被多视图代理时,无法同步数据修改。 * 无法做到深度观测和深度监听。 * 更新对象中某个数据时,会导致整个对象属性都刷新,导致程序运行缓慢。
709 4
【HarmonyOS Next】状态管理V2版本使用详解
|
SQL Unix API
夏令时的坑:你的数据库真的能正确处理时间跳变吗?
时区是地球上使用相同标准时间的区域。由于地球的自转,为了保证各地的时间与当地的日出日落相协调,全球划分为多个时区。
787 0
|
存储 云安全 供应链
云计算有哪6个未来发展趋势?
在全球云计算产业迅猛增长的背景下,社交网络的普及使其社会化功能成为未来热点。六大发展趋势包括:1) 移动设备推动云计算广泛应用;2) 第三方云平台崛起,提供更多选择;3) 云计算助力企业减少损耗,提升效率;4) 新一轮价格战即将爆发,竞争加剧;5) 云存储成为主流,数据访问更便捷;6) 社交化特征增强,促进企业与客户便捷沟通。云计算正迎来新时代,企业需积极拥抱技术,实现数字化转型。
1589 1
|
Web App开发 前端开发
前端下载文件(Blob)的几种方式使用Blob下载文件
前端下载文件(Blob)的几种方式使用Blob下载文件
1770 0
|
机器学习/深度学习 数据采集 算法
监督学习工作流程:从数据准备到模型部署
本文详细介绍了监督学习的工作流程,涵盖数据准备、模型选择、训练、评估与优化、部署等关键步骤,并结合具体代码示例,帮助读者全面掌握监督学习在实际项目中的应用方法。从数据收集、清洗到特征工程,再到模型训练与评估,最后部署模型,每个环节都提供了详细的指导和实践建议。适合初学者和有一定基础的读者深入学习。
1246 2
|
前端开发 JavaScript
前端 JS 经典:大文件分片
前端 JS 经典:大文件分片
490 0
|
JavaScript 前端开发
height、clientHeight、scrollHeight、offsetHeight区别
height、clientHeight、scrollHeight、offsetHeight区别
564 0
height、clientHeight、scrollHeight、offsetHeight区别

热门文章

最新文章