繁体   English   中英

RxJava 中的 concatMap 和 flatMap 有什么区别

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

看起来这两个功能非常相似。 它们具有相同的签名(接受rx.functions.Func1<? super T, ? extends Observable<? extends R>> func ),并且它们的rx.functions.Func1<? super T, ? extends Observable<? extends R>> func图看起来完全相同。 无法在此处粘贴图片,但这里是concatMap 的一张,这是flatMap的一张。 结果Observable的描述似乎有一些细微的差异,其中concatMap生成的包含连接结果 Observable 的项目,而flatMap生成的项目包含首先合并生成的 Observable 并发出结果的项目那个合并。

然而,我完全不清楚这种微妙之处。 任何人都可以更好地解释这种差异,并且最好给出一些说明这种差异的例子。


正如您所写,这两个函数非常相似,细微的区别在于输出的创建方式(在应用映射函数之后)。

平面地图使用合并运算符,而 concatMap 使用concat 运算符

如您所见, concatMap 输出序列是有序的 - 第一个 Observable 发出的所有项目在第二个 Observable 发出的任何项目之前发出,
当 flatMap 输出序列被合并时 - 合并的 Observable 发出的项目可能以任何顺序出现,无论它们来自哪个源 Observable。

尽管这里的答案很好,但如果没有示例,也不容易发现差异。 因此,我为此创建了一个简单的示例:

@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的结果是无序的。

一个非常重要的区别: concatMap等待当前发出的 observable 完成而flatMap不会。 flatMap尝试尽可能多地启动。 简单地说 - 你不能连接无限的东西。 只需确保您在concatMap发出的concatMap可以完成,否则整个流程将卡住等待当前 observable 完成以连接下一个。

我发现大多数赞成的答案中的例子不太清楚,所以我发布了一个帮助我理解 flatMap 和 concatMap 之间区别的例子。

FlatMap需要排放源可观察到的,然后创建新观察到的,其合并到原来的链条,而concatMap它Concat的原始链。

主要区别在于 concatMap() 将按顺序合并每个映射的 Observable 并一次触发一个。 只有当当前 Observable 调用 onComplete() 时,它才会移动到下一个 Observable。

这是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()默认在计算调度器上运行

首先,flatMap 与 Rxjs 中的 mergeMap 相同。 所以这少了一种混淆。 所以有两个 observable..

1) o1:来自(['Kitty','Donald','Batman']) 的简单项目列表

2) process_o1(): process_o1() 是一个函数,它接受一个参数“item”并用它做一些事情并返回一个 Observable,它在完成时发出“done with [item]”。

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

在这里,我们将看到:- 用 Kity 完成。

完成与唐纳德。

完成与蝙蝠侠。

不能保证凯蒂先于唐纳德,唐纳德先于蝙蝠侠。 这是因为,一旦外部 observable 发出一个项目,内部 observable 就会被订阅。

=== 但是在 concatMap 的情况下:-

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

我们有以下顺序的保证:-

与凯蒂完成。

完成与唐纳德。

完成与蝙蝠侠。

因为,使用 concatMap 运算符,在前一个内部 Observable 返回之前,内部 Observable 不会被订阅。

外部 observable 可以自由地继续并发出它的所有值,但是 concatMap 将确保它一个一个地处理这些值中的每一个并保持顺序。 因此名称为 concatMap。

关键是,如果你热衷于维护做事的顺序,你应该使用concatMap。 但是如果你不关心顺序,你可以继续使用 mergeMap 它会立即订阅所有内部 Observables 并在它们返回时继续发出值。

flatMap 与 concatMap

flatMap - 合并 - 如果发出新项目,则它具有优先级

concatMap - 连接 - 添加到最后 - 发出完整序列,只有在那之后(前一个完成)才能发出下一个序列

[地图与平面地图]

其他人已经指出了答案,但如果不是太明显,则可能会使用 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