似乎这两个功能非常相似。它们具有相同的签名(接受rx.functions.Func1<? super T, ? extends Observable<? extends R>> func
),并且它们的大理石图看起来完全相同。无法在此处粘贴图片,但这里是concatMap的图片,而flatMap就是一张图片。结果Observable
的描述中似乎存在一些细微的差别,其中concatMap
生成的一个包含由结合的Observable生成的项,而flatMap
生成的项包含结果的项首先合并生成的Observable,然后发出合并的结果。
然而,这种微妙之处对我来说完全不清楚。任何人都可以更好地解释这种差异,并且最好给出一些说明这种差异的例子。
答案 0 :(得分:48)
正如您所写,这两个函数非常相似,细微差别在于如何创建输出(在应用映射函数之后)。
平面地图使用merge operator,而concatMap使用concat operator。
如您所见,concatMap输出序列是有序的 - 第一个Observable发出的所有项目都是在第二个Observable发出的任何项目之前发出的, 当flatMap输出序列合并时 - 合并的Observable发出的项可以按任何顺序出现,无论它们来自哪个源Observable。
答案 1 :(得分:12)
一个非常重要的区别:concatMap
等待当前发出的observable完成,而flatMap
没有。flatMap
。 concatMap
尝试尽可能多地开始。简单地说 - 你无法连接无限的东西。 只需确保您在loadData
中发出的可观察量可以完成,否则整个流程将停滞等待当前的observable完成以连接下一个。
答案 2 :(得分:7)
即使这里的答案很好,但没有示例也不容易发现差异。因此,我为此创建了一个简单的示例:
@Test
public void flatMapVsConcatMap() throws Exception {
System.out.println("******** Using flatMap() *********");
Observable.range(1, 15)
.flatMap(item -> Observable.just(item).delay(1, TimeUnit.MILLISECONDS))
.subscribe(x -> System.out.print(x + " "));
Thread.sleep(100);
System.out.println("\n******** Using concatMap() *********");
Observable.range(1, 15)
.concatMap(item -> Observable.just(item).delay(1, TimeUnit.MILLISECONDS))
.subscribe(x -> System.out.print(x + " "));
Thread.sleep(100);
}
********使用flatMap()*********
1 2 3 4 5 6 7 9 8 11 13 15 10 12 14
********使用concatMap()*********
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
从输出中可以看到,flatMap
的结果是无序的,而concatMap
的结果却是无序的。
答案 3 :(得分:7)
我发现大多数投票答案中的示例不太清楚,因此我发布了一个示例,帮助我理解了flatMap和concatMap之间的区别。
FlatMap从可观察的源中获取排放,然后创建新的可观察并合并到原始链,而concatMap concat 到原始链。
主要区别在于concatMap()将合并 每个映射的Observable都按顺序进行,并一次触发一次。它只会移动到 当当前一个调用onComplete()时,下一个可观察到。
这是 flatMap 示例:
private void flatMapVsConcatMap() throws InterruptedException {
Observable.just(5, 2, 4, 1)
.flatMap(
second ->
Observable.just("Emit delayed with " + second + " second")
.delay(second, TimeUnit.SECONDS)
)
.subscribe(
System.out::println,
Throwable::printStackTrace
);
Thread.sleep(15_000);
}
将导致:
发射延迟了1秒
发射延迟2秒
发射延迟4秒
发射延迟5秒
这是 concatMap 示例:
private void flatMapVsConcatMap() throws InterruptedException {
Observable.just(5, 2, 4, 1)
.concatMap(
second ->
Observable.just("Emit delayed with " + second + " second")
.delay(second, TimeUnit.SECONDS)
)
.subscribe(
System.out::println,
Throwable::printStackTrace
);
Thread.sleep(15_000);
}
将导致:
发射延迟5秒
发射延迟2秒
发射延迟4秒
发射延迟了1秒
请注意使用Thread.sleep(),因为 delay()默认在计算调度程序上运行
答案 4 :(得分:0)
首先,flatMap与Rxjs中的mergeMap相同。这样就少了一个混乱。 因此,有两个可观测值。
1)o1:((['Kitty','Donald','Batman'])
中的物品的简单列表2)process_o1():process_o1()是一个将参数“ item”作为参数并对其进行处理并返回Observable的函数,该Observable在完成时发出“与[item]完成”。
o1.pipe(mergeMap(item => process_o1(item))).subscribe(data => {
console.log(data);
});
在这里,我们将看到: 由Kity完成。
与唐纳德完成。
与蝙蝠侠完成。
不保证凯蒂(Kitty)在唐纳德(Donald)之前,唐纳德(Donald)在蝙蝠侠(Batman)之前。 这是因为,一旦外部可观察物发射出一个项目,内部可观察物即为 已订阅。
=== 但是如果使用concatMap:-
o1.pipe(concatMap(item => process_o1(item))).subscribe(data => {
console.log(data);
});
我们保证以下顺序:-
与Kity完成。
与唐纳德完成。
与蝙蝠侠完成。
因为使用concatMap运算符,内部Observable在先前的内部Observable返回之前没有被订阅。
外部可观察对象可以自由地继续前进并发出其所有值,但是concatMap将确保它逐一处理每个这些值并保持顺序。 因此,名称为concatMap。
在症结所在,如果您热衷于维护服务的顺序,则应该使用concatMap。 但是,如果您不关心顺序,则可以继续使用mergeMap,它将立即订阅所有内部Observable并在它们返回时继续发出值。
答案 5 :(得分:0)
flatMap 与 concatMap
flatMap
- 合并 - 如果发出新项目,则它具有优先权
concatMap
- 连接 - 添加到最后 - 发出完整序列,只有在那之后(前一个完成)才能发出下一个序列