rxjs中的flatMap,mergeMap,switchMap和concatMap?

diE*_*cho 24 observable rxjs

有人请用Javascript解释SwitchMap和FlatMap之间的区别(角度透视,rxjs 5)

在我的理解中.

SwitchMap仅发出最新的可观察值并取消之前的可观察值.

faltMap收集所有单独的observable并返回单个数组中的所有observable,而不关心可观察的顺序.异步工作.

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

是对的吗?

如何做mergeMap从上面的工作方式不同?

有人,请举例说明.

Yil*_*maz 32

假设您订阅了天气频道。气象播音员宣读了经过多次操作后传递给他的报告。

  • 如果播音员正在阅读一份报告,而在阅读另一份报告时进来。如果他停止阅读第一份报告并在新报告到达后立即开始阅读,那么他正在做switchMap。因为switchMap将每个源值投影到一个可观察值,该可观察值合并到输出可观察值中,所以仅从最近投影的可观察值发出值。

  • 如果广播播音员在第一个报告完成之前才开始新的报告,那么我们有concatMapconcatMap将每个源值投影到一个可观察量,该可观察量以序列化方式合并到输出可观察量中,等待每个源值完成,然后再合并下一个。

  • 如果在播音员仍在朗读时收到新的报告,而他的反应是同时朗读两份报告,那么我们就可以了mergeMap/flatMap。( flatMap 是 mergeMap 的别名)。因为mergeMap将每个源值投影到一个可观察量,该可观察量将合并到输出可观察量中。“mergeMap”是 switchMap 和 concatMap 的更基本版本。

  • 很好的比喻。感谢你的回答 (4认同)

Zah*_*hiC 23

之前的答案中得到这个:

  • flatMap/mergeMap - 立即为任何源项创建一个Observable,所有以前的Observable都保持活动状态
  • concatMap - 在创建下一个Observable之前等待之前的Observable完成
  • switchMap - 对于任何源项,完成前一个Observable并立即创建下一个
  • exhaustMap - 在前一个Observable未完成时忽略源项

下面是一个示例,说明当源是直接项(0,1,2,3,4)时每个运算符的行为,并且map函数创建一个将每个项延迟500ms的Observable:

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);
Run Code Online (Sandbox Code Playgroud)
.examples > div {
  cursor: pointer;
  background-color: #4CAF50;
  color: white;
  padding: 7px 16px;
  display: inline-block;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

  • 令人难以置信的答案,喜欢这个片段。 (7认同)
  • 非常感谢您提供了这样一个美丽的例子。 (2认同)
  • @MarcinPevik `flatMap` 是 `mergeMap` 的别名,这就是它打印出 `mergeMap` 的原因。`flatMap` 将从 v8 中的 RxJS 中删除。 (2认同)

jad*_*adc 17

这是思考不同类型地图之间差异的另一种方式。这帮助我理解了它。我希望它可以帮助其他人。

考虑以下来源:

  • 从字母表中生成小写字母的源:a、b、c 和 d
  • 4 个独立的“单词”源,每个源产生 3 个单词,以字母表中的特定字母(a、b、c 或 d)开头,然后完成

为了说明不同类型的地图之间的差异,我们将把字母表源中的项目链接到与字母表中的字母相对应的“单词”源,使用每个不同的地图来查看不同的结果。

地图

这与其他地图不同,因为它没有引入其他可观察源。它只是将传入值转换为另一个值。

因此,小写源的输出,通过将输入转换为大写的 Map,将是:

Input: a,b,c,d

Output: A, B, C, D
Run Code Online (Sandbox Code Playgroud)

切换地图

这将每个输入转换为另一个源,将输出切换为来自该新源(即订阅该新源)。当另一个 alpha 输入到达时,“word”源会发生变化(我们取消订阅先前的“word”源)。

Input: a,b,c,d

Output: animal, aardvark, bull, baker, beach, cow, dog, day, dinner
Run Code Online (Sandbox Code Playgroud)

康卡特地图

与 switchMap 类似,只不过 Concat 会等到每个源完成后再继续下一个。

Input: a,b,c,d

Output: animal, aardvark, axe, bull, baker, beach, cow, car, cat, dog, day, dinner
Run Code Online (Sandbox Code Playgroud)

排气图

与 Concat Map 类似,只不过它会忽略在完成最后一个源时传入的任何输入。下面的示例假设 alpha 输入“b”和“d”均在前一个映射源仍在完成时进入,因此它们被忽略。

Input: a,b,c,d

Output: animal, aardvark, axe, cow, car, cat
Run Code Online (Sandbox Code Playgroud)

合并地图(又名平面地图)

与 concatMap 一样,每个源都运行完成,但新源可以在其他源仍在运行时启动 - 因此序列重叠。

Input: a,b,c,d

Output: animal, aardvark, bull, axe, baker, cow, car, beach, dog, day, cat, dinner
Run Code Online (Sandbox Code Playgroud)


kos*_*kos 16

在下面的大理石图中,以5ms10ms20ms发射的源流将*映射为a timer(0, 3),限制为3种发射:

mergeMap,exhaustMap,switchMap,concatMap

在这里玩这个大理石图:“ mergeMap vs exhaustMap vs switchMap vs concatMap”

已经有了所有这些很棒的答案,我想添加一个更直观的解释

希望对别人有帮助

  • 大理石是使用可观察物的最佳方式。这些答案很多对其他人来说毫无意义 (4认同)

Ric*_*sen 15

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

外部,内部和控制

这些运算符都像是转换运算符map(),其共同特征是它们具有可观察的内部外部。关键区别在于外部可观察者控制内部可观察者的方式。

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


mergeMap vs concatMap

这些都输出所有值,不同之处在于顺序

mergeMap-通过内部可观察的
[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遵循严格的外部发射序列。


switchMap vs exhaustMap

这些都限制输出。

switchMap-最后
[3,0],[4,0],[4,1]进行 节流

exhaustMap-先按
[0,0],[0,1],[4,0],[4,1] 节气门

从输出中,switchMap会限制所有不完整的内部发射,但是exhaustMap会限制随后的发射,直到较早的内部发射完成。


mergeMap vs switchMap

我之所以这样说是因为switchmap通常用于应该真正使用mergeMap的SO答案中。

mergeMap-通过内部可观察的
[0,0],[1,0],[0,1],[2,0],[1,1],[3,0],[2,1],[4]进行排序,0],[3,1],[4,1]

switchMap-最后
[3,0],[4,0],[4,1]进行 节流

主要结论是switchMap输出取决于内部可观察到的时间是不可预测的,例如,如果内部是http,则结果可能取决于连接速度。


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));
Run Code Online (Sandbox Code Playgroud)
.examples > div {
  cursor: pointer;
  background-color: #4CAF50;
  color: white;
  padding: 7px 16px;
  display: inline-block;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)


Ham*_*Ali 7

  1. switchMap - 停止处理订单并开始处理新订单。只有最新的订单才会完成。

  2. concatmap - 订单被添加到队列中。您可以完成正在处理的任何订单。完成订单后,您将处理下一个订单。

  3. mergeMap - 一旦收到所有订单,您将同时处理所有订单。

  4. exhausMap - 您忽略新订单并完成您正在处理的任何订单。完成后,您可以自由接受新订单。


kno*_*fel 6

我不久前制作了一个使用请求的运算符的小演示/示例。

https://stackblitz.com/edit/rxjs-map-operators

您可以选择间隔或单击来发出外部可观察值。对于内部可观察,您可以选择是否发出间隔(3 个项目)或 http 请求。

它将在选择下方打印结果。


Pic*_*cci 5

这在开始时有点长,至少对我来说是这样。

无论如何,考虑一下:

flatMapIS ANOTHER NAME FOR mergeMap-mergeMap方法接受一个可选参数concurrency,该参数定义可以同时订阅多少个 Observable

concatMap等于mergeMap并发设置为 1

mergeMap你不能失去你合并的观发出任何情况下,你在你的答案建议

switchMap如您所描述的那样工作(有关更多详细信息,参阅这篇不错的文章https://blog.angular-university.io/rxjs-switchmap-operator/