在rxJs中与flatMap vs concatMap进行斗争

布格

我正在努力了解rxJsflatMap之间的concatMap区别。

我能理解的最明确的答案是,concatmap和flatmap之间的差异

所以我自己去尝试了一些事情。

import "./styles.css";
import { switchMap, flatMap, concatMap } from "rxjs/operators";
import { fromFetch } from "rxjs/fetch";
import { Observable } from "rxjs";

function createObs1() {
  return new Observable<number>((subscriber) => {
    setTimeout(() => {
      subscriber.next(1);
      subscriber.complete();
    }, 900);
  });
}

function createObs2() {
  return new Observable<number>((subscriber) => {
    setTimeout(() => {
      subscriber.next(2);
      //subscriber.next(22);
      //subscriber.next(222);
      subscriber.complete();
    }, 800);
  });
}

function createObs3() {
  return new Observable<number>((subscriber) => {
    setTimeout(() => {
      subscriber.next(3);
      //subscriber.next(33);
      //subscriber.next(333);
      subscriber.complete();
    }, 700);
  });
}

function createObs4() {
  return new Observable<number>((subscriber) => {
    setTimeout(() => {
      subscriber.next(4);
      subscriber.complete();
    }, 600);
  });
}

function createObs5() {
  return new Observable<number>((subscriber) => {
    setTimeout(() => {
      subscriber.next(5);
      subscriber.complete();
    }, 500);
  });
}

createObs1()
  .pipe(
    flatMap((resp) => {
      console.log(resp);
      return createObs2();
    }),
    flatMap((resp) => {
      console.log(resp);
      return createObs3();
    }),
    flatMap((resp) => {
      console.log(resp);
      return createObs4();
    }),
    flatMap((resp) => {
      console.log(resp);
      return createObs5();
    })
  )
  .subscribe((resp) => console.log(resp));

console.log("hellooo");

我在这里用过那个操场的例子

问题

1)据我了解,flatMap的使用应混合使用输出,以便控制台日志类似于(1、3、2、4、5)。我已经尝试了30次以上,并且总是排在同一行(1、2、3、4、5)

我在做错什么还是在不懂得做错什么?

2)如果启用,createObs2()然后createObs3()删除注释,并在代码中包含多个发出的事件,那么事情将变得混乱。即使您更改为concatMap,它也会使事情变得混乱,并且结果会混杂在一起。我希望只有一次的多个数字会多次出现。结果可能是(1、2、33、3、2、22、3、33、4、5、4、3、4、5)为什么会发生这种情况?

我如何在操场上测试示例。我只从最后一个console.log(“ hello”)中删除了1个字母。仅观察到一次更改,例如console.log(“ heloo”),然后再次编译项目,并在控制台中输出输出。

编辑:我去flatMap和concatMap的原因是使用http库在angular中找到嵌套订阅的替代方法。

createObs1().subscribe( (resp1) => {
          console.log(resp1);
          createObs2().subscribe( (resp2) => {
               console.log(resp2);
               createObs3().subscribe( (resp3) => {
                   console.log(resp3);
                   createObs4().subscribe( (resp4) => {
                        console.log(resp4);
                        createObs5().subscribe( (resp5) => {
                            console.log(resp5);
                            })
                        })
                   })
               })
             })
比兹鲍勃

您的测试方案确实不足以看到这两个运算符之间的差异。在您的测试用例中,每个可观察对象仅发出1次。如果一个observable只发出一个值,那么concatMapand flatMapaka mergeMap之间确实没有区别仅当存在多个排放时才能看到差异。

因此,让我们使用另一种情况。让我们有一个source$可观察的对象,它仅每1秒发出一个递增的整数。然后,在我们的“高阶映射运算符”(concatMapmergeMap)中,我们将返回一个可观察对象,该对象每1秒发出一次可变的次数,然后完成。

// emit number every second
const source$ = interval(1000).pipe(map(n => n+1)); 

// helper to return observable that emits the provided number of times
function inner$(max: number, description: string): Observable<string> {
  return interval(1000).pipe(
    map(n => `[${description}: inner source ${max}] ${n+1}/${max}`),
    take(max), 
  );
}

然后让我们基于source$定义两个单独的可观察对象inner$一种使用concatMap,另一种使用flatMap并观察输出。

const flatMap$ = source$.pipe(
    flatMap(n => inner$(n, 'flatMap$'))
);

const concatMap$ = source$.pipe(
    concatMap(n => inner$(n, 'concatMap$'))
);

在查看输出差异之前,让我们谈谈这些运算符的共同点。他俩:

  • 订阅传入的函数返回的可观察对象
  • 从这种“内部可观察到的”发射出排放物
  • 取消订阅内部可观察的对象

不同之处在于它们如何创建和管理内部订阅:

concatMap-一次只允许一个内部订阅。当它接收到发射时,一次只能订阅一个内部可观察到的信号。因此,它最初将订阅“排放1”创建的可观测对象,只有完成后,才订阅“排放2”创建的可观测对象。这与concat静态方法的行为一致

flatMapakamergeMap)-允许许多内部订阅。因此,它将在收到新的排放量时订阅内部的可观测值。这意味着发射将不会按照任何特定的顺序进行,因为只要其任何内部可观察到的发射都将发射。这与merge静态方法的行为是一致的这就是为什么我个人更喜欢使用名称“ mergeMap”)。

这是一个StackBlitz,显示上述可观察物concatMap$的输出mergeMap$concatMap与mergeMap

希望以上说明有助于您解决问题!

#1-“使用flatMap应该混合输出

之所以无法按您预期的那样工作,是因为只有一个发射正在通过flatMap,这意味着您只有一个“内部可观察”的发射值。如上例所示,flatMap收到多个发射后,便可以具有多个独立发射的内部可观测对象。

#2-“ ...并且将代码包含多个发出的事件,那么事情就变得混乱了。

“事情变得混乱”是由于具有多个内部订阅,这些订阅发出了值。

对于您提到的使用concatMap并仍然获得“混合”输出的部分,我不希望如此。启用“自动保存”后,我在StackBlitz中看到了奇怪的行为,并观察到了发射现象(似乎有时它不能完全刷新,而旧的订阅似乎在自动刷新后仍然存在,这会带来非常混乱的控制台输出)。也许代码沙箱也有类似的问题。

#3-“我之所以去flatMap和concatMap的原因是使用http库找到了angular嵌套订阅的替代品

这是有道理的。您不想弄乱嵌套的订阅,因为没有什么好方法可以保证内部订阅会被清除。

在大多数使用http调用的情况下,我发现这switchMap是理想的选择,因为它将减少您不再关心的内部可观察对象的发射。想象一下,您有一个id从路由参数读取的组件它使用它id进行http调用以获取数据。

itemId$ = this.activeRoute.params.pipe(
    map(params => params['id']),
    distinctUntilChanged()
);

item$ = this.itemId$.pipe(
    switchMap(id => http.get(`${serverUrl}/items/${id}`)),
    map(response => response.data)
);

我们只想item$发出“当前项”(对应于url中的id)。假设我们的用户界面有一个按钮,用户可以单击该按钮导航至下一个项目,id并且您的应用程序会发现自己是一个不断点击该按钮的点击满意用户,因此更改URL参数的速度甚至比http调用返回数据的速度更快。

如果选择mergeMap,我们将最终获得许多内部可观察到的东西,这些可观察到的东西将发出所有这些HTTP调用的结果。充其量,当所有这些不同的呼叫返回时,屏幕将闪烁。最坏的情况下(如果调用无序),UI将显示与url中的ID不同步的数据:-(

如果选择concatMap,则即使我们只在乎最近的一个,用户也将被迫等待所有的http调用完成。

但是,有了switchMap,每当itemId收到新的发射()时,它将取消订阅先前的内部可观察对象,并订阅新的。这意味着它将永远不会从不再相关的旧http调用中发出结果。:-)

有一点要注意的是,由于HTTP观测只能发出一次(不同运营商之间的选择switchMapmergeMapconcatMap)就显得不有所作为,因为他们都执行“内部观察的处理”对我们来说。但是,最好是将来对代码进行过时验证,并选择一个能够真正为您提供所需行为的代码,如果您开始收到的不止一个发射代码。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Rxjs使用concatMap进行顺序调用

来自分类Dev

Rxjs使用concatMap进行顺序调用

来自分类Dev

concatMap 与 flatMap

来自分类Dev

在我的Meteor应用中与.find()和.findOne()进行斗争

来自分类Dev

Rxjs:concatMap中的条件延迟

来自分类Dev

RxJava-Flatmap vs ConcatMap-为什么在订购时订购相同的商品?

来自分类Dev

复杂策略中的@composite vs flatmap

来自分类Dev

RxJava中的concatMap和flatMap有什么区别

来自分类Dev

rxjs中mergeMap和concatMap的混合

来自分类Dev

在c中与fputc斗争

来自分类Dev

在Flutter中与authStateChanges斗争

来自分类Dev

与 Python 中的 API 斗争

来自分类Dev

如何在VS 2019,VS 2017和VS 2015中进行简单的VS扩展安装并正常工作?

来自分类Dev

单个项目的concatMap,flatMap,switchMap

来自分类Dev

使用队列和列表 STL 与 C++ 分配进行斗争。无法将数据填充到列表或队列中,然后打印该数据

来自分类Dev

在Android Studio中与JDBC斗争

来自分类Dev

无法在VS 2012中进行调试。VS正在重新启动

来自分类Dev

在VS Code上使用Node.js和RXJS进行简单的测试项目

来自分类Dev

如何从 RxJs 中的 flatMap 返回附加值

来自分类Dev

在VS 2013中对unique_ptr的向量进行排序

来自分类Dev

与VS 2019中的最新版本进行比较

来自分类Dev

RxJS 6 - flatMap 条件

来自分类Dev

Groovy中的“ vs”,“ vs”,“ vs”和“ vs”。何时使用什么?

来自分类Dev

与angular中的rxjs进行组件交互

来自分类Dev

关于铁轨中TDD(BDD)的斗争

来自分类Dev

正确使用 flatMap - mergeMap 或 concatMap 会更高效

来自分类常见问题

在Angular rxjs中,什么时候应该使用`pipe` vs`map`

来自分类Dev

RXJS flatMap可重复观察

来自分类Dev

极限vs存在vs count(*)vs count(id)在MySQL中

Related 相关文章

热门标签

归档