简体   繁体   English

RxJava 中的 concatMap 和 flatMap 有什么区别

[英]What is the difference between concatMap and flatMap in RxJava

It seems that these 2 functions are pretty similar.看起来这两个功能非常相似。 They have same signature (accepting rx.functions.Func1<? super T, ? extends Observable<? extends R>> func ), and their marble diagrams look exactly same.它们具有相同的签名(接受rx.functions.Func1<? super T, ? extends Observable<? extends R>> func ),并且它们的rx.functions.Func1<? super T, ? extends Observable<? extends R>> func图看起来完全相同。 Can't paste the pics here, but here's one for concatMap , and here's one for flatMap .无法在此处粘贴图片,但这里是concatMap 的一张,这是flatMap的一张。 There seems to be some subtle difference in the description of resulting Observable , where one produced by concatMap contains items that result from concatinating resulting Observables, and the one produced by flatMap contains items that result from first merging the resulting Observables, and emitting the result of that merger.结果Observable的描述似乎有一些细微的差异,其中concatMap生成的包含连接结果 Observable 的项目,而flatMap生成的项目包含首先合并生成的 Observable 并发出结果的项目那个合并。

However, this subtlety is totally unclear to me.然而,我完全不清楚这种微妙之处。 Can anyone give a better explanation of this difference, and ideally give some examples illustrating this difference.任何人都可以更好地解释这种差异,并且最好给出一些说明这种差异的例子。


As you wrote, the two functions are very similar and the subtle difference is how the output is created ( after the mapping function is applied).正如您所写,这两个函数非常相似,细微的区别在于输出的创建方式(在应用映射函数之后)。

Flat map uses merge operator while concatMap uses concat operator .平面地图使用合并运算符,而 concatMap 使用concat 运算符

As you see the concatMap output sequence is ordered - all of the items emitted by the first Observable being emitted before any of the items emitted by the second Observable,如您所见, concatMap 输出序列是有序的 - 第一个 Observable 发出的所有项目在第二个 Observable 发出的任何项目之前发出,
while flatMap output sequence is merged - the items emitted by the merged Observable may appear in any order, regardless of which source Observable they came from.当 flatMap 输出序列被合并时 - 合并的 Observable 发出的项目可能以任何顺序出现,无论它们来自哪个源 Observable。

Even though the answers here are good it wasn't easy to spot the difference without an example.尽管这里的答案很好,但如果没有示例,也不容易发现差异。 So, I created a simple example for this:因此,我为此创建了一个简单的示例:

@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);
}

******** Using flatMap() ********* ******** 使用 flatMap() *********

1 2 3 4 5 6 7 9 8 11 13 15 10 12 14 1 2 3 4 5 6 7 9 8 11 13 15 10 12 14

******** Using concatMap() ********* ******** 使用 concatMap() *********

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

As it could be seen from the output, the results for flatMap are unordered while for concatMap they're.从输出中可以看出, flatMap的结果是无序的,而concatMap的结果是无序的。

One very important difference: the concatMap waits for the current emitted observable to complete and flatMap doesn't.一个非常重要的区别: concatMap等待当前发出的 observable 完成而flatMap不会。 flatMap tries to start as many possible. flatMap尝试尽可能多地启动。 Simply said - you cannot concatenate something infinite.简单地说 - 你不能连接无限的东西。 Just make sure that the observables you emit in concatMap can complete , otherwise the whole flow will get stuck waiting for the current observable to complete to concatenate the next one.只需确保您在concatMap发出的concatMap可以完成,否则整个流程将卡住等待当前 observable 完成以连接下一个。

I find example in most upvoted answer not much clear, so i post one that helped me to understand difference between flatMap and concatMap.我发现大多数赞成的答案中的例子不太清楚,所以我发布了一个帮助我理解 flatMap 和 concatMap 之间区别的例子。

FlatMap takes emissions from source observable, then create new observable and merge it to original chain, while concatMap concat it to original chain. FlatMap需要排放源可观察到的,然后创建新观察到的,其合并到原来的链条,而concatMap它Concat的原始链。

Main difference is that concatMap() will merge each mapped Observable sequentially and fire it one at a time.主要区别在于 concatMap() 将按顺序合并每个映射的 Observable 并一次触发一个。 It will only move to the next Observable when the current one calls onComplete().只有当当前 Observable 调用 onComplete() 时,它才会移动到下一个 Observable。

Here is flatMap example:这是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);
}

Will result in :将导致:

Emit delayed with 1 second发射延迟 1 秒
Emit delayed with 2 second发射延迟 2 秒
Emit delayed with 4 second发射延迟 4 秒
Emit delayed with 5 second发射延迟 5 秒

Here is concatMap example:这是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);
}

Will result in :将导致:

Emit delayed with 5 second发射延迟 5 秒
Emit delayed with 2 second发射延迟 2 秒
Emit delayed with 4 second发射延迟 4 秒
Emit delayed with 1 second发射延迟 1 秒

Note to use Thread.sleep() because delay() operates by default on the computation Scheduler注意使用 Thread.sleep()因为delay()默认在计算调度器上运行

First of all, flatMap is same as mergeMap in Rxjs.首先,flatMap 与 Rxjs 中的 mergeMap 相同。 So that is one confusion less.所以这少了一种混淆。 So there are two observables..所以有两个 observable..

1) o1: A simple list of items from(['Kitty','Donald','Batman']) 1) o1:来自(['Kitty','Donald','Batman']) 的简单项目列表

2) process_o1(): process_o1() is a function that takes as one parameter 'item' and does something with it and returns an Observable which on completion emits 'done with [item]'. 2) process_o1(): process_o1() 是一个函数,它接受一个参数“item”并用它做一些事情并返回一个 Observable,它在完成时发出“done with [item]”。

o1.pipe(mergeMap(item => process_o1(item))).subscribe(data => {
console.log(data);
});

Here we are going to see:- done with Kity.在这里,我们将看到:- 用 Kity 完成。

done with Donald.完成与唐纳德。

done with Batman.完成与蝙蝠侠。

without any guarantee that Kitty comes before Donald and Donald comes before Batman.不能保证凯蒂先于唐纳德,唐纳德先于蝙蝠侠。 This is because, as soon as the outer observable emits an item the inner observable is subscribed.这是因为,一旦外部 observable 发出一个项目,内部 observable 就会被订阅。

=== But in case of concatMap:- === 但是在 concatMap 的情况下:-

o1.pipe(concatMap(item => process_o1(item))).subscribe(data => {
console.log(data);
});

We have the guarantee of the below sequence:-我们有以下顺序的保证:-

done with Kity.与凯蒂完成。

done with Donald.完成与唐纳德。

done with Batman.完成与蝙蝠侠。

Because, with concatMap operator, the inner Observable is not subscribed before the previous inner Observable returns.因为,使用 concatMap 运算符,在前一个内部 Observable 返回之前,内部 Observable 不会被订阅。

The outer observable is free to just go ahead and emit all its values, but the concatMap will make sure that it deals with each of those values one by one and maintains the order.外部 observable 可以自由地继续并发出它的所有值,但是 concatMap 将确保它一个一个地处理这些值中的每一个并保持顺序。 Hence the name concatMap.因此名称为 concatMap。

In crux, if you are keen on maintaining the order of doing things, you should use concatMap.关键是,如果你热衷于维护做事的顺序,你应该使用concatMap。 But if you dont care about order, you can go ahead with mergeMap which will subscribe to all inner Observables at once and keep emitting values as and when they return.但是如果你不关心顺序,你可以继续使用 mergeMap 它会立即订阅所有内部 Observables 并在它们返回时继续发出值。

flatMap vs concatMap flatMap 与 concatMap

flatMap - merge - if new item is emitted it has a priority flatMap - 合并 - 如果发出新项目,则它具有优先级

concatMap - concatenate - add into the end - emit full sequence and only after that(previous was finished) is able to emit next sequence concatMap - 连接 - 添加到最后 - 发出完整序列,只有在那之后(前一个完成)才能发出下一个序列

[map vs flatMap] [地图与平面地图]

其他人已经指出了答案,但如果不是太明显,则可能会使用 flatMap 创建不需要的并行性,如果不需要,您可以使用 concatMap 或重载flatMap(Function<? super T,? extends Publisher<? extends V>> mapper, int concurrency)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM