简体   繁体   English

rxjs 中的 flatMap、mergeMap、switchMap 和 concatMap?

[英]flatMap, mergeMap, switchMap and concatMap in rxjs?

Someone, please explain the difference between SwitchMap and FlatMap in terms of Javascript ( in angular perspective, rxjs 5)请哪位大神解释一下Javascript(在angular视角下,rxjs 5)中SwitchMap和FlatMap的区别

In my understanding.在我的理解中。

SwitchMap only emits the latest observable value and cancels the previous observable. SwitchMap仅发出最新的可观察值并取消先前的可观察值。

flatMap collects all individual observables and returns all observables in a single array without caring about the order of observable. flatMap收集所有单独的 observable 并在一个数组中返回所有 observable,而不关心 observable 的顺序。 works asynchronously.异步工作。

concatMap preserve the order and emits all observable value, works synchronously concatMap保留顺序并发出所有可观察值,同步工作

is that right?是对的吗?

how does mergeMap works differently from above? mergeMap与上面的工作方式有何不同?

someone, please explain with an example.有人,请举例说明。

Taking this from a previous answer :以前的答案中提取:

  • flatMap/mergeMap - creates an Observable immediately for any source item, all previous Observables are kept alive flatMap/mergeMap - 立即为任何源项创建一个 Observable,所有先前的 Observable 都保持活动状态
  • concatMap - waits for the previous Observable to complete before creating the next one concatMap - 在创建下一个 Observable 之前等待前一个 Observable 完成
  • switchMap - for any source item, completes the previous Observable and immediately creates the next one switchMap - 对于任何源项,完成前一个 Observable 并立即创建下一个
  • exhaustMap - source items are ignored while the previous Observable is not completed ExhaustMap - 当前一个 Observable 未完成时,源项目将被忽略

Here is an example of how each of the operators behaves when the source is immediate items (0,1,2,3,4) and the map function creates an Observable that delays each item by 500ms:这是一个示例,说明当源是直接项 (0,1,2,3,4) 并且 map 函数创建一个将每个项延迟 500 毫秒的 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);
 .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>

In the marble diagram below a source stream that emits at 5ms , 10ms , 20ms will be *Mapped to a timer(0, 3) , limited to 3 emissions:在下面的弹珠图中,在5ms10ms20ms发射的源流将被*映射timer(0, 3) ,限制为 3 个发射:

mergeMap 与exhaustMap 与switchMap 与concatMap

Play with this marble diagram here: "mergeMap vs exhaustMap vs switchMap vs concatMap"在这里玩这个大理石图: “mergeMap vsexhaustMap vs switchMap vs concatMap”

Already having all these awesome answers, I wanted to add a more visual explanation已经有了所有这些很棒的答案,我想添加一个更直观的解释

Hope it helps someone希望它可以帮助某人

@ZahiC, cool answer - I like the use of functional composition in the code sample. @ZahiC,很酷的答案 - 我喜欢在代码示例中使用函数组合。 If I may, like to borrow it to illustrate a couple of extra points using timed observables.如果可以的话,我想借用它来使用定时观察来说明一些额外的要点。

Outer, inner, and control外部、内部和控制

These operators are all transformation operators like map() , the common feature is they have an outer and inner observable.这些操作符都是像map()这样的转换操作符,共同的特点是它们有一个外层内层的observable。 The key difference is the way the outer observable controls the inner observable.关键的区别在于外部 observable控制内部 observable 的方式。

To contrast them, my code sample runs them in pairs, outputting values in the form [outerValue,innerValue] .为了对比它们,我的代码示例成对运行它们,以[outerValue,innerValue]的形式输出值。 I have added intervals to the test, and changed the inner delay so that there's some overlap in timing (formula used is delay((5-x)*200) ).我在测试中添加了间隔,并更改了内部延迟,以便在时间上有一些重叠(使用的公式是delay((5-x)*200) )。


mergeMap vs concatMap mergeMap 与 concatMap

These both output all values , the difference is the ordering .这些都输出所有值,不同的是排序

mergeMap - Order by inner observable mergeMap - 按内部 observable 排序
[0,0],[1,0],[0,1],[2,0],[1,1],[3,0],[2,1],[4,0],[3,1],[4,1] [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 concatMap - 按外部 observable 排序
[0,0],[0,1],[1,0],[1,1],[2,0],[2,1],[3,0],[3,1],[4,0],[4,1] [0,0],[0,1],[1,0],[1,1],[2,0],[2,1],[3,0],[3,1],[4 ,0],[4,1]

From the output, mergeMap outer emit can be delayed in the sequence, but concatMap follows strict outer emit sequence.从输出来看,mergeMap 外发射可以在序列中延迟,但 concatMap 遵循严格的外发射序列。


switchMap vs exhaustMap switchMap vs 排气映射

These both throttle the output.这些都限制了输出。

switchMap - Throttle by last switchMap - 最后节流
[3,0],[4,0],[4,1] [3,0],[4,0],[4,1]

exhaustMap - Throttle by first排气地图 - 首先节流
[0,0],[0,1],[4,0],[4,1] [0,0],[0,1],[4,0],[4,1]

From the output, switchMap throttles any incomplete inner emits, but exhaustMap throttles following emits until the earlier ones complete.从输出中,switchMap 会限制任何不完整的内部发射,但exhaustMap 会限制后续的发射,直到较早的发射完成。


mergeMap vs switchMap mergeMap 与 switchMap

I threw this in because switchmap is often used in SO answers where really mergeMap should be used.我之所以这样做是因为 switchmap 经常用在真正应该使用 mergeMap 的 SO 答案中。

mergeMap - Order by inner observable mergeMap - 按内部 observable 排序
[0,0],[1,0],[0,1],[2,0],[1,1],[3,0],[2,1],[4,0],[3,1],[4,1] [0,0],[1,0],[0,1],[2,0],[1,1],[3,0],[2,1],[4,0],[3 ,1],[4,1]

switchMap - Throttle by last switchMap - 最后节流
[3,0],[4,0],[4,1] [3,0],[4,0],[4,1]

The main takeaway is that the switchMap output is unpredictable depending on the timing of the inner observable, eg if the inner is an http get the results can depend on connection speed.主要的收获是 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));
 .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>

This is at the beginning a bit long to grasp, at least for me.这在开始时有点长,至少对我来说是这样。

Anyways, consider this:无论如何,考虑一下:

flatMap IS ANOTHER NAME FOR mergeMap - mergeMap method accepts an optional parameter concurrency , which defines how many Observables can be subscribed at the same time flatMapmergeMap mergeMap名称 - mergeMap方法接受一个可选参数concurrency ,它定义了可以同时订阅多少个 Observables

concatMap equals mergeMap with concurrency set to 1 concatMap等于并发设置为 1 的mergeMap

with mergeMap you do not lose any event emitted by the Observables you are merging as you suggested in your answer使用mergeMap您不会丢失您在回答中建议的合并的 Observables 发出的任何事件

switchMap works as you have described (see this nice article for more details https://blog.angular-university.io/rxjs-switchmap-operator/ ) switchMap像您描述的switchMap工作(有关更多详细信息,参阅这篇不错的文章https://blog.angular-university.io/rxjs-switchmap-operator/

I made a little demo/example for using the requested operators a while ago.不久前,我制作了一个使用请求的运算符的小演示/示例。

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

You can choose between an interval or click for emiting outer observable values.您可以选择间隔或单击以发出外部可观察值。 For the inner observable you can choose whether to emit an interval (3 items) or a http request.对于内部 observable,您可以选择是发出间隔(3 项)还是 http 请求。

It will print the results below the selection.它将在选择下方打印结果。

Let's say you are subscribed to a weather channel.假设您订阅了一个天气频道。 weather announcer reads the report that passed to him after run through several operations.天气播音员阅读了经过几次操作后传递给他的报告。

  • If the announcer is reading one report and while reading another report comes in. If he stops reading the first report and begins to read the new report as soon as it arrives then he is doing switchMap .如果播音员正在阅读一份报告,而在阅读另一份报告时进来。如果他停止阅读第一份报告并在新报告到达时立即开始阅读,那么他正在执行switchMap Because switchMap projects each source value to an observable which is merged in the output observable, emitting values only from the most "recently" projected observable.因为switchMap将每个源值投影到一个 observable 中,该 observable 合并在输出 observable 中,所以仅从最近“最近”投影的 observable 中发出值。

  • if the radio announcer does not begin a new report until the first one is finished, we have concatMap .如果广播播音员直到第一个报告完成后才开始新报告,我们有concatMap concatMap projects each source value to an observable which is merged in the output observable in a serialized fashion waiting for each one to complete before merging the next. concatMap将每个源值投影到一个 observable 中,该 observable 以序列化的方式合并到输出 observable 中,等待每个值完成后再合并下一个。

  • if a new report comes in while the announcer is still reading and his response is somehow to read both at the same time then we have mergeMap/flatMap .如果在播音员仍在阅读时mergeMap/flatMap新报告,并且他的回应是以某种方式同时阅读两者,那么我们就有了mergeMap/flatMap ( flatMap is an alias for mergeMap). ( flatMap 是 mergeMap 的别名)。 Because mergeMap projects each source value to an observable which is merged in the output observable.因为mergeMap将每个源值投影到一个 observable 中,该 observable 合并在输出 observable 中。 "mergeMap" is a more basic version of switchMap and concatMap. “mergeMap”是 switchMap 和 concatMap 的更基本版本。

Here is one more way of thinking about the difference between the different types of maps.这是另一种思考不同类型地图之间差异的方式。 This helped me get my head around it.这帮助我理解了它。 I hope it might help others.我希望它可以帮助其他人。

Consider the following sources:考虑以下来源:

  • A source producing lower case letters from the alphabet: a,b,c & d从字母表中产生小写字母的来源:a,b,c & d
  • 4 separate "word" sources, each one producing 3 words starting with a particular letter from the alphabet - a,b,c or d - then completing 4 个独立的“词”源,每个源产生 3 个词,以字母表中的特定字母开头 - a、b、c 或 d - 然后完成

To illustrate the difference between different kinds of maps, we will link items from the alphabet source to their "word" sources corresponding to that letter of the alphabet, using each different map to see the different outcomes.为了说明不同类型地图之间的差异,我们将把字母源中的项目链接到对应于该字母的“词”源,使用每个不同的地图来查看不同的结果。

Map 地图

This is unlike the other maps because it does not introduce another source of observable.这与其他地图不同,因为它没有引入另一个可观察的来源。 It just transforms an incoming value to another value.它只是将传入的值转换为另一个值。

So output from the lower case source, going through a Map which transforms input to upper case, would just be:因此,来自小写源的输出,通过将输入转换为大写的 Map,将是:

Input: a,b,c,d

Output: A, B, C, D

Switch Map 切换地图

This transforms each input into another source, switching output to come from that new source (ie subscribing to that new source).这会将每个输入转换为另一个源,将输出切换为来自该新源(即订阅该新源)。 When another alpha input arrives, the "word" source changes (we unsubscribe from the previous "word" source).当另一个 alpha 输入到达时,“word”源会发生变化(我们取消订阅之前的“word”源)。

Input: a,b,c,d

Output: animal, aardvark, bull, baker, beach, cow, dog, day, dinner

Concat Map 康卡特地图

Like switchMap except that Concat waits until each source completes before moving on to the next.与 switchMap 类似,除了 Concat 等待每个源完成后再继续下一个。

Input: a,b,c,d

Output: animal, aardvark, axe, bull, baker, beach, cow, car, cat, dog, day, dinner

Exhaust Map 排气图

Like Concat Map except that it will ignore any inputs that come in while it is still completing the last source.与 Concat Map 类似,除了它在完成最后一个源时会忽略任何输入。 The example below assumes that the alpha inputs "b" and "d" both came in while the previous mapped source was still completing, so they were ignored.下面的示例假设 alpha 输入“b”和“d”都在前一个映射源仍在完成时传入,因此它们被忽略。

Input: a,b,c,d

Output: animal, aardvark, axe, cow, car, cat

Merge Map (aka Flat Map) 合并地图(又名平面地图)

Like concatMap in that each source runs to completion, but a new source can start up while other sources are still going - so the sequences overlap.就像 concatMap 一样,每个源都运行到完成,但是一个新的源可以在其他源仍在运行时启动 - 因此序列重叠。

Input: a,b,c,d

Output: animal, aardvark, bull, axe, baker, cow, car, beach, dog, day, cat, dinner
  1. switchMap - Stop working on the order and start working on the new order. switchMap - 停止处理订单并开始处理新订单。 Only the latest order will eve be finished.只有最新的订单才能完成。

  2. concatmap - The order gets added to a queue. concatmap - 订单被添加到队列中。 You finish whatever order you're working on.你完成你正在处理的任何订单。 Once you finish the order, you will work on the next order.完成订单后,您将处理下一个订单。

  3. mergeMap - You will work on all orders at the same time as soon as you're given them. mergeMap - 一旦获得订单,您将同时处理所有订单。

  4. exhaustMap - You ignore new orders and finish whatever order you're working on. exhaustMap - 您忽略新订单并完成您正在处理的任何订单。 Once finished, you are free to accept new orders.完成后,您可以自由接受新订单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM