---
title: '[Layout] Two columns'
---
::::info
**介紹switchMap和concatMap的使用情境與差異**
:::spoiler 目錄 :
描述
>- [描述](#描述)
switchMap
>- [說明](#switchMap-說明)
>- [特性](#switchMap-特性)
>- [使用情境](#switchMap-使用情境)
concatMap
>- [說明](#concatMap-說明)
>- [特性](#concatMap-特性)
>- [使用情境](#concatMap-使用情境)
switchMap和concatMap差異
>- [差異](#差異)
>- [範例](#範例)
結論
>- [總結](#結論)
:::
::::
<style>
.two-column-layout {
column-count: 2; /* Set column number */
column-gap: 20px;
max-width: 100%;
overflow: hidden;
}
/* Media query for mobile devices */
@media (max-width: 768px) {
.two-column-layout {
column-count: 1; /* Switch to single column on small screens */
column-gap: 0; /* Optional: Set gap to 0 for single column */
}
}
.markdown-body, .ui-infobar {
max-width: unset !important;
}
.two-column-layout ul,
.two-column-layout ol {
margin: 0;
padding-left: 20px;
}
.two-column-layout strong {
font-weight: bold;
}
.two-column-layout em {
font-style: italic;
}
.two-column-layout h1,
.two-column-layout h2,
.two-column-layout h3,
.two-column-layout h4,
.two-column-layout h5,
.two-column-layout h6 {
margin-top: 0;
}
</style>
# 描述
`switchMap`和`concatMap`都會處理來自源 Observable 的每一個元素並返回一個新的 Observable,簡單來說就是如果你要同個時間處理多個異步Observable可以使用。
- 如果你希望 同時處理多個異步操作,但只關心最新的結果,使用 `switchMap`。
- 如果你希望 依次處理多個異步操作,且確保每個操作完成後再處理下一個,使用 `concatMap`。
# switchMap
## `switchMap` 說明
`switchMap` 是 RxJS 中的一個操作符,常用於處理異步事件流,特別是在需要 **取消舊請求並只保留最新請求** 的場景,例如 **即時搜尋 (autocomplete)**。
---
## `switchMap` 特性
🟢 **當新的 observable 進來時,會取消前一個**(避免並行請求)。
🟢 **只保留最新的 observable 結果**,確保最新資料可用。
🟢 **適用於 快速變動的輸入**(如表單輸入、鍵盤事件)。
---
## `switchMap` 使用情境
### 🔎 即時搜尋 (autocomplete)
使用者在輸入框輸入關鍵字時,每次輸入都會發送一個 API 請求,但我們只想要最後一次輸入的結果,而不是所有請求的結果。
### 🚀 避免多次請求覆蓋
當使用者頻繁點擊按鈕時,`switchMap` 可以確保 **只保留最後一次點擊觸發的請求結果**,不會有多餘的回應。
# concatMap
## `concatMap` 說明
`concatMap` 是 RxJS 中的一個操作符,**用於確保每個 observable 順序執行**,適合需要 **前一個請求完成後才執行下一個請求** 的場景,例如 **API 需串聯執行的請求**。
---
## `concatMap` 特性
🟢 **每個 observable 會按順序執行,上一個完成後才執行下一個**。
🟢 **適合需要保持請求順序的場景**(如 API 依賴前一個結果時)。
🟢 **確保不會同時發送多個請求,避免競態條件 (race conditions)**。
---
## `concatMap` 使用情境
### 🔗 依序執行 API 請求
當一個 API 需要依賴前一個請求的結果時,`concatMap` 可確保請求按照順序執行,避免請求交錯導致錯誤。
### 🚛 批次處理請求
當需要一次發送多個請求,且每個請求都必須**等前一個完成後再執行**(例如依序上傳檔案),`concatMap` 可以確保不會同時發送多個請求,減少伺服器負擔。
---
# concatMap和switchMap 差異
## 差異
| operator | 特性 | 適合場景 |
|------------|---------------------------------------------------------|-----------------------------------------------|
| `switchMap` | 前一個 observable 還沒結束時,如果來新的,**直接取消**前一個 | 避免多重觸發,取最新(像 Input欄位及時驗證API) |
| `concatMap` | 一個 observable **執行完才接下一個**,順序保證 | API 要確保串接、保證前後順序時 |
## 範例
描述:要一次打兩個API
- concatMap 版本
```
this.doPostData() // 1️⃣ 執行 doPostData(),取得第一個 API 資料
.pipe(
take(1), // 只取一次
tap((res) => this.processPostData(res)), // 2️⃣ 這裡可以取得doPostData() 的資料,並處理
concatMap(() => this.doPostTableData()), // 3️⃣ 等 doPostData 完全完成後,再接續 doPostTableData
finalize(() => this.commonService.setLoadingFlag(false))
)
.subscribe((res) => { // 4️⃣ 這裡一樣拿到 doPostTableData() 的結果
this.groupData = res.data.list;
this.setPageInfo(res.data);
if (Object.keys(this.groupData).length === 0) {
alert('查無資料');
}
});
```
- concatMap 流程圖
```
開始
↓
執行 doPostData() (API 1)
↓
處理 API 1 資料 (tap -> processPostData)
↓
執行 doPostTableData() (API 2)(concatMap)
↓
關閉 Loading (finalize)
↓
處理 API 2 資料 (subscribe -> groupData, setPageInfo)
↓
資料為空? → 是 → 顯示提示訊息 (alert)
↓ 否
結束
```
- switchMap 版本
```
this.doPostData() // 1️⃣ 執行 doPostData(),取得第一個 API 資料
.pipe(
take(1), // 只取一次
tap((res) => this.processPostData(res)), // 2️⃣ 這裡可以取得 doPostData() 的資料,並處理
switchMap(() => this.doPostTableData()), // 3️⃣ 再接著執行第二個 API
finalize(() => this.commonService.setLoadingFlag(false)) // 4️⃣ 兩個 API 都跑完或失敗時關閉 loading
)
.subscribe((res) => { // 5️⃣ 這裡的 res 是 **doPostTableData() 的資料**
this.groupData = res.data.list;
this.setPageInfo(res.data); // 設定分頁資訊
if (Object.keys(this.groupData).length === 0) {
alert('查無資料');
}
});
```
- switchMap流程圖
```
開始
↓
執行 doPostData() (API 1)
↓
處理 API 1 資料 (tap -> processPostData)
↓
執行 doPostTableData() (API 2)(switchMap)
↓
關閉 Loading (finalize)
↓
處理 API 2 資料 (subscribe -> groupData, setPageInfo)
↓
資料為空? → 是 → 顯示提示訊息 (alert)
↓ 否
結束
```
- 流程差異總結
| 特性 | switchMap | concatMap |
|--------------------|--------------------------------------|----------------------------------------|
| 內部 Observable 行為 | 取消之前的 Observable,訂閱最新的 | 排隊執行,確保每個 Observable 順序執行 |
| 適用場景 | 即時性操作,例如搜尋建議 | 需要確保執行順序,例如多步驟 API 流程 |
| 資料處理順序 | 可能跳過中間的資料處理 | 確保每個資料按順序處理 |
| 優點 | 避免處理過時資料,提升即時性 | 確保執行順序,適合依賴前一步結果的流程 |
| 缺點 | 可能導致資料丟失 | 可能增加延遲,因為需要等待前一步完成 |
---
# 結論
- 如果需要確保 API 執行的順序,應使用 `concatMap`。
- 如果只需要最新的結果,且不在意中間的資料被取消,應使用 `switchMap`。