编程在于折腾

【译】Map 与 FlatMap 的对比

这篇博客主要讨论RxJS中Map和FlatMap的区别。

阅读或在工作使用RxJS的人一定会遇到RxJS中各式各样的操作符(operators)。包括但不限于:

  1. of - 该操作符将参数列表简单地转换为Observable序列
  2. from - 从一个数组或者可迭代的对象中创建Observable序列。
  3. map - 转换Observable序列中的每一个元素。可以简单地将该方法比作Array实例的map方法。
  4. subscribe - 这个操作符主要是ObserverObservable两者的连接点

上面这些是最常用的,你可以知道更多新的操作符。

我之前遇到过一种使用Observables中的Observable(嵌套Observable)的情景,我想要获取单流输出。为了解决这个问题,接下来介绍另外的有趣操作符。

flatMap - 它主要将observable序列中的observable序列合并成单个observable序列。

所以,让我们来看看一段代码,看其是如何工作的。我们有一个访问者数组,如下:

let visitors = [
"Namita",
"Amit",
"Rohit",
"Neetika"
];

现在,我想要这个数组被转换为一个Observable序列,所以它可以像下面一样解决:

let source = Rx.Observable.from(visitors)
.map(x => 'Hello ' + x);

让我们来订阅这个序列:

source.subscribe(x => document.getElementById('flatMap').innerText += x + "\n");

视图将会如下所示:

map-flatMap.png

map-flatMap.png

但是我们想解决的是如何使observable序列中的observable能正确处理,所以我们给上述代码做点改变:

let source = Rx.Observable.from(visitors)
.map(x => Rx.Observable.of('Hello ' + x));

然而我们的视图将会如下面图片一样(不正确地显示):

Map-error.png

Map-error.png

所以应该如何修复? 那我们就要使用flatMap操作符了:

let source = Rx.Observable.from(visitors)
.flatMap(x => Rx.Observable.of('Hello ' + x));

现在我们就可以像之前那样简单地订阅,即可得到我们期望的结果:

map-flatMap.png

map-flatMap.png

所以,mapflatMap的区别是什么:

map将方法应用于Observable发射(emit)出的items转换为单个元素的item,而flatmap是:

  1. 发射出的每一个值运用特定方法,该特定方法将每一个值处理为一个Observable(序列)并依次返回
  2. flatMap然后将所有这些序列合并成一个新的单一序列。

让我们来使用ASCII珠宝图梳理一下上述的区别,或许更加通熟易懂。

----Namita---Amit---Rohit---Neetika----- //Input Stream
.map(x => 'Hello ' + x);
---Hello Namita---Hello Amit---Hello Rohit---Hello Neetika--- //Map's function result

----Namita---Amit---Rohit---Neetika----- //Input Stream
.flatMap(x => Rx.Observable.of('Hello ' + x))
--Hello Namita-- //transforming each input element into an Observable
--Hello Amit--
--Hello Rohit--
--Hello Neetika--
---Hello Namita---Hello Amit---Hello Rohit---Hello Neetika--- // Flatmap's final result

当需要处理observables中的observable(嵌套)的情况的时候,也可以使用另外的操作符mergeAll,和map搭配使用。这与直接使用flatMap的效果是一样的。 RxJS有着大量的操作符,希望这次学习之旅能帮到我们每一个人…继续快乐地学习。