簡體   English   中英

rxjs 中的 flatMap、mergeMap、switchMap 和 concatMap?

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

請哪位大神解釋一下Javascript(在angular視角下,rxjs 5)中SwitchMap和FlatMap的區別

在我的理解中。

SwitchMap僅發出最新的可觀察值並取消先前的可觀察值。

flatMap收集所有單獨的 observable 並在一個數組中返回所有 observable,而不關心 observable 的順序。 異步工作。

concatMap保留順序並發出所有可觀察值,同步工作

是對的嗎?

mergeMap與上面的工作方式有何不同?

有人,請舉例說明。

以前的答案中提取:

  • flatMap/mergeMap - 立即為任何源項創建一個 Observable,所有先前的 Observable 都保持活動狀態
  • concatMap - 在創建下一個 Observable 之前等待前一個 Observable 完成
  • switchMap - 對於任何源項,完成前一個 Observable 並立即創建下一個
  • ExhaustMap - 當前一個 Observable 未完成時,源項目將被忽略

這是一個示例,說明當源是直接項 (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>

在下面的彈珠圖中,在5ms10ms20ms發射的源流將被*映射timer(0, 3) ,限制為 3 個發射:

mergeMap 與exhaustMap 與switchMap 與concatMap

在這里玩這個大理石圖: “mergeMap vsexhaustMap vs switchMap vs concatMap”

已經有了所有這些很棒的答案,我想添加一個更直觀的解釋

希望它可以幫助某人

@ZahiC,很酷的答案 - 我喜歡在代碼示例中使用函數組合。 如果可以的話,我想借用它來使用定時觀察來說明一些額外的要點。

外部、內部和控制

這些操作符都是像map()這樣的轉換操作符,共同的特點是它們有一個外層內層的observable。 關鍵的區別在於外部 observable控制內部 observable 的方式。

為了對比它們,我的代碼示例成對運行它們,以[outerValue,innerValue]的形式輸出值。 我在測試中添加了間隔,並更改了內部延遲,以便在時間上有一些重疊(使用的公式是delay((5-x)*200) )。


mergeMap 與 concatMap

這些都輸出所有值,不同的是排序

mergeMap - 按內部 observable 排序
[0,0],[1,0],[0,1],[2,0],[1,1],[3,0],[2,1],[4,0],[3 ,1],[4,1]

concatMap - 按外部 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 排氣映射

這些都限制了輸出。

switchMap - 最后節流
[3,0],[4,0],[4,1]

排氣地圖 - 首先節流
[0,0],[0,1],[4,0],[4,1]

從輸出中,switchMap 會限制任何不完整的內部發射,但exhaustMap 會限制后續的發射,直到較早的發射完成。


mergeMap 與 switchMap

我之所以這樣做是因為 switchmap 經常用在真正應該使用 mergeMap 的 SO 答案中。

mergeMap - 按內部 observable 排序
[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));
 .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>

這在開始時有點長,至少對我來說是這樣。

無論如何,考慮一下:

flatMapmergeMap mergeMap名稱 - mergeMap方法接受一個可選參數concurrency ,它定義了可以同時訂閱多少個 Observables

concatMap等於並發設置為 1 的mergeMap

使用mergeMap您不會丟失您在回答中建議的合並的 Observables 發出的任何事件

switchMap像您描述的switchMap工作(有關更多詳細信息,參閱這篇不錯的文章https://blog.angular-university.io/rxjs-switchmap-operator/

不久前,我制作了一個使用請求的運算符的小演示/示例。

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

您可以選擇間隔或單擊以發出外部可觀察值。 對於內部 observable,您可以選擇是發出間隔(3 項)還是 http 請求。

它將在選擇下方打印結果。

假設您訂閱了一個天氣頻道。 天氣播音員閱讀了經過幾次操作后傳遞給他的報告。

  • 如果播音員正在閱讀一份報告,而在閱讀另一份報告時進來。如果他停止閱讀第一份報告並在新報告到達時立即開始閱讀,那么他正在執行switchMap 因為switchMap將每個源值投影到一個 observable 中,該 observable 合並在輸出 observable 中,所以僅從最近“最近”投影的 observable 中發出值。

  • 如果廣播播音員直到第一個報告完成后才開始新報告,我們有concatMap concatMap將每個源值投影到一個 observable 中,該 observable 以序列化的方式合並到輸出 observable 中,等待每個值完成后再合並下一個。

  • 如果在播音員仍在閱讀時mergeMap/flatMap新報告,並且他的回應是以某種方式同時閱讀兩者,那么我們就有了mergeMap/flatMap ( flatMap 是 mergeMap 的別名)。 因為mergeMap將每個源值投影到一個 observable 中,該 observable 合並在輸出 observable 中。 “mergeMap”是 switchMap 和 concatMap 的更基本版本。

這是另一種思考不同類型地圖之間差異的方式。 這幫助我理解了它。 我希望它可以幫助其他人。

考慮以下來源:

  • 從字母表中產生小寫字母的來源:a,b,c & d
  • 4 個獨立的“詞”源,每個源產生 3 個詞,以字母表中的特定字母開頭 - a、b、c 或 d - 然后完成

為了說明不同類型地圖之間的差異,我們將把字母源中的項目鏈接到對應於該字母的“詞”源,使用每個不同的地圖來查看不同的結果。

地圖

這與其他地圖不同,因為它沒有引入另一個可觀察的來源。 它只是將傳入的值轉換為另一個值。

因此,來自小寫源的輸出,通過將輸入轉換為大寫的 Map,將是:

Input: a,b,c,d

Output: A, B, C, D

切換地圖

這會將每個輸入轉換為另一個源,將輸出切換為來自該新源(即訂閱該新源)。 當另一個 alpha 輸入到達時,“word”源會發生變化(我們取消訂閱之前的“word”源)。

Input: a,b,c,d

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

康卡特地圖

與 switchMap 類似,除了 Concat 等待每個源完成后再繼續下一個。

Input: a,b,c,d

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

排氣圖

與 Concat Map 類似,除了它在完成最后一個源時會忽略任何輸入。 下面的示例假設 alpha 輸入“b”和“d”都在前一個映射源仍在完成時傳入,因此它們被忽略。

Input: a,b,c,d

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

合並地圖(又名平面地圖)

就像 concatMap 一樣,每個源都運行到完成,但是一個新的源可以在其他源仍在運行時啟動 - 因此序列重疊。

Input: a,b,c,d

Output: animal, aardvark, bull, axe, baker, cow, car, beach, dog, day, cat, dinner
  1. switchMap - 停止處理訂單並開始處理新訂單。 只有最新的訂單才能完成。

  2. concatmap - 訂單被添加到隊列中。 你完成你正在處理的任何訂單。 完成訂單后,您將處理下一個訂單。

  3. mergeMap - 一旦獲得訂單,您將同時處理所有訂單。

  4. exhaustMap - 您忽略新訂單並完成您正在處理的任何訂單。 完成后,您可以自由接受新訂單。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM