关于rxjs中的observable:flatMap,mergeMap,switchMap和concatMap?

flatMap, mergeMap, switchMap and concatMap in rxjs?

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

以我的理解。

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

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

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

那正确吗?

mergeMap与上面的工作原理有何不同?

有人,请举例说明。


从先前的答案中得出:

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
1
2
3
4
5
6
7
.examples > div {
  cursor: pointer;
  background-color: #4CAF50;
  color: white;
  padding: 7px 16px;
  display: inline-block;
}
1
2
3
4
5
6
7
8
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.8/Rx.js">


  mergeMap
  flatMap
  concatMap
  switchMap
  exhaustMap


在下面的大理石图中,以5ms,10ms,20ms发射的源流将被*映射为timer(0, 3),限于3种发射:

mergeMap vs exhaustMap vs switchMap vs concatMap

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

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

希望对别人有帮助


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

外部,内部和控制

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

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

mergeMap vs concatMap

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

mergeMap - Order by inner observable
[0,0],[1,0],[0,1],[2,0],[1,1],[3,0],[2,1],[4,0],[3,1],[4,1]

concatMap - Order by outer observable
[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 - Throttle by last
[3,0],[4,0],[4,1]

exhaustMap - Throttle by first
[0,0],[0,1],[4,0],[4,1]

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

mergeMap vs switchMap

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

mergeMap - Order by inner observable
[0,0],[1,0],[0,1],[2,0],[1,1],[3,0],[2,1],[4,0],[3,1],[4,1]

switchMap - Throttle by last
[3,0],[4,0],[4,1]

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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));
1
2
3
4
5
6
7
.examples > div {
  cursor: pointer;
  background-color: #4CAF50;
  color: white;
  padding: 7px 16px;
  display: inline-block;
}
1
2
3
4
5
6
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.8/Rx.js">


  mergeMap vs concatMap
  switchMap vs exhaustMap
  mergeMap vs switchMap


至少对于我来说,这刚开始需要很长时间。

无论如何,请考虑以下几点:

flatMapmergeMap的另一个名称-mergeMap方法接受可选参数concurrency,该参数定义可以同时预订多少个Observable

concatMap等于mergeMap,并发设置为1

使用mergeMap,您不会丢失正在合并的Observable发出的任何事件,就像您在答案中所建议的那样

switchMap可以按照您所描述的进行工作(有关更多详细信息,请参见这篇不错的文章https://blog.angular-university.io/rxjs-switchmap-operator/)


我做了一个使用请求的运算符的演示/示例。

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

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