当前位置: 首页 > 知识库问答 >
问题:

rxjs中的flatMap、mergeMap、switchMap和concatMap?

秦诚
2023-03-14

有人,请解释一下SwitchMap和FlatMap在Javascript方面的区别(在角度透视图中,rxjs 5)

以我的理解。

SwitchMap仅发出最新的可观察值,并取消先前的可观察值。

flatMap收集所有单独的可观测数据,并在单个数组中返回所有可观测数据,而不关心可观测数据的顺序。异步工作。

concatMap保持秩序并发出所有可观察值,同步工作

是这样吗?

mergeMap与上面的工作方式有什么不同?

有人,请举例说明。

共有3个答案

艾浩穰
2023-03-14

@ZahiC,很酷的回答-我喜欢在代码示例中使用函数组合。如果可以的话,我想借用它来说明几个额外的点使用定时观测。

这些操作符都是变换操作符,比如map(),它们的共同特点是具有外部和内部可观察性。关键的区别在于外部可观察物控制内部可观察物的方式。

为了对比它们,我的代码示例成对运行它们,以[outerValue, innerValue]的形式输出值。我在测试中添加了间隔,并更改了内部延迟,以便在定时上有一些重叠(使用的公式是延迟((5-x)*200))。

这两个都输出所有值,区别在于顺序。

合并映射-内部可观测的顺序
[0,0],[1,0],[0,1],[2,0],[1,1],[3,0],[2,1],[4,0],[3,1],[4,1]

ConcatMap-由外部可观测
[0,0],[0,1],[1,0],[1,1],[2,0],[2,1],[3,0],[3,1],[4,0],[4,1]排序

从输出中,mergeMap外部发射可以在序列中延迟,但是concatMap遵循严格的外部发射序列。

这两个节流输出。

开关图-最后一次节流
[3,0],[4,0],[4,1]

排气图-通过第一个节气门
[0,0],[0,1],[4,0],[4,1]

我加入这个是因为切换映射经常用于SO答案中,在这些答案中应该使用真正的合并映射。

合并映射-内部可观测的顺序
[0,0],[1,0],[0,1],[2,0],[1,1],[3,0],[2,1],[4,0],[3,1],[4,1]

开关图-最后一次节流
[3,0],[4,0],[4,1]

主要的收获是,switchMap输出是不可预测的,这取决于内部可观测的时间,例如,如果内部是http get,则结果可能取决于连接速度

console.clear()
const { mergeMap, flatMap, concatMap, switchMap, exhaustMap, delay, map, take, toArray } = Rx.operators;

const note = {
  mergeMap:  'Order by inner observable', 
  concatMap: 'Order by outer observable', 
  switchMap: 'Throttle by last', 
  exhaustMap: 'Throttle by first', 
}
const title = (operator) => {
  const opName = operator.name.replace('$1','')
  return `${opName} - ${note[opName]}`
}
const display = (x) => {
  return map(y => `[${x},${y}]`)
}
const inner = (x) => Rx.Observable.timer(0,500)
.pipe(
  delay((5-x)*200),
  display(x),
  take(2)
)

const example = operator => () => {
  Rx.Observable.interval(500).take(5)
  .pipe(
    operator(x => inner(x)),
    toArray(),
    map(vals => vals.join(','))
  )
  .subscribe(x => {
    console.log(title(operator))
    console.log(x)
  });
};

const run = (fn1, fn2) => {
  console.clear()
  fn1()
  fn2()
}
const mmVcm = () => run(example(mergeMap), example(concatMap));
const smVem = () => run(example(switchMap), example(exhaustMap));
const mmVsm = () => run(example(mergeMap), example(switchMap));
.examples > div {
  cursor: pointer;
  background-color: #4CAF50;
  color: white;
  padding: 7px 16px;
  display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.8/Rx.js"></script>

<div class='examples'>
  <div onClick='mmVcm()'>mergeMap vs concatMap </div>
  <div onClick='smVem()'>switchMap vs exhaustMap</div>
  <div onClick='mmVsm()'>mergeMap vs switchMap </div>
</div>
乐正光誉
2023-03-14

在下面的大理石图中,以5ms、10ms、20ms发射的源流将*映射到计时器(0,3),限制为3次发射:

在这里玩这个大理石图:“合并地图vs用尽地图vs切换地图vs连接地图”

已经有了这些令人敬畏的答案,我想添加一个更直观的解释

希望对某人有所帮助

仲孙思源
2023-03-14

根据之前的回答:

  • flatMap/mergeMap-立即为任何源项创建一个可观察项,所有以前的可观察项保持活动状态

下面是一个示例,说明了当源为立即项(0,1,2,3,4)且映射函数创建一个可观测项时,每个操作符的行为方式,该项可观测项将延迟500毫秒:

const { mergeMap, flatMap, concatMap, switchMap, exhaustMap } = Rx.operators;

const example = operator => () =>
  Rx.Observable.from([0,1,2,3,4])
  .pipe(
    operator(x => Rx.Observable.of(x).delay(500))
  )
  .subscribe(console.log, () => {}, () => console.log(`${operator.name} completed`));

const mm = example(mergeMap);
const fm = example(flatMap);
const cm = example(concatMap);    
const sm = example(switchMap);
const em = example(exhaustMap);
.examples > div {
  cursor: pointer;
  background-color: #4CAF50;
  color: white;
  padding: 7px 16px;
  display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.8/Rx.js"></script>

<div class='examples'>
  <div onClick='mm()'>mergeMap </div>
  <div onClick='fm()'>flatMap</div>
  <div onClick='cm()'>concatMap</div>
  <div onClick='sm()'>switchMap</div>
  <div onClick='em()'>exhaustMap</div>
</div>
 类似资料:
  • 我们有一个执行http请求的请求服务。所有请求都实现IRequest接口,该接口包含http方法和一个执行函数,该函数依次返回另一个可观察的对象。 RequestService有一个重载,它接受一个源可观察对象,还有一个requestfactory,它根据源可观察对象的值返回一个IRequest实例。 当然,在服务中做了更多的工作(日志记录、默认错误处理,...),但大多数与问题无关。 现在,这一

  • switchmap的rxjava文档定义相当模糊,它链接到与FlatMap相同的页面。这两个操作员有什么不同?

  • 我正在努力理解rxJs中的平面图和连续图之间的区别。 我能理解的最清楚的答案是concatmap和flatmap之间的区别 所以我自己去试了试。 我用这里的操场操场作为例子 问题 1)根据我的理解,平面图的使用应该混合输出,这样控制台日志就像(1,3,2,4,5)。我尝试了30多次,总是出现在同一行(1, 2, 3, 4, 5) 我做错了什么,或者我做错了什么? 2)如果在和上删除注释并包含包含多

  • 当我使用Angular HttpClient发出GET请求时,我得到一个可观察的返回,并在RxJS操作符mergeMap中处理它。 现在一次又一次地抛出404,我想抓住它。最后,浏览器控制台中不应出现错误消息,并且应使用流的下一个值处理管道。 这有可能吗?我没有用catchError()管理它。 以下是我的代码的简化版本: 更新:添加了带有catchError()的方法 我尝试过这种方式,但没有检

  • 我有一条可以观察到的溪流。第一个运算符是一个mergeMap,它返回一个可观察的数组。然后,我必须有第二个mergeMap从第一个mergeMap的返回中获取最终值。我觉得这第二个合并映射应该是不必要的,但找不到绕过它的方法。 例子: 这最终是我所拥有的。第二个mergeMap只存在于订阅第一个的输出。没有它,我的输出是可观察的(即(1)的

  • 我有以下方法: 和批准的排放方法: 我得到这样的错误,当我试图链我的rxjs请求: [at loader]中出错/src/app/auth/intercept/auth。拦截器。ts:18:16 TS2345:类型为“(res:any)的参数= 如何正确链接此请求?不要同时使用平面贴图链。map()和。error()方法?我可以用这种方式链接请求吗?因为我需要从我的请求方法(其自定义Http实现)