3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RxJSオペレータ(mergeMap, switchMap, concatMap)使い分けガイド

Last updated at Posted at 2025-07-08

はじめに

アイスタイルでバックエンドを担当しているkuriyamayです。

最近RxJSを使用したプロダクトを作成し、本番環境へリリース・安定稼動するところまでやりました。
その間に様々なインプットがあったので、ここでアウトプットしていこうと思います。

本記事のRxJSはバージョン7.8.1を使用しています

RxJSとは

RxJSについては2024年のアドベントカレンダー記事をご覧ください。

オペレータの分類

RxJSオペレータは、Observableの生成や変換を行う関数で、大きく2種類に分かれます。

分類 説明
Pipeable Operators .pipe() の中で使われ、既存の Observable を変換・操作するオペレータ。例: map, filter, mergeMap
Creation Operators 非Observableな値(配列、数値、Promiseなど)から Observable を生成するオペレータ。例: of, from, interval

今回はPipeable OperatorsのMapオペレータについて説明していきます。

Mapオペレータとは

複数種類のMapオペレータがあり、その中でもどれを使えばいいか迷ってしまう下記3つのMapオペレータを取り上げます。

  • mergeMap
  • concatMap
  • switchMap

mergeMap, concatMap, switchMap はすべて 「外側の Observable の各値を元に、新しい Observable を生成し、それを flatten(平坦化)して処理する」 という性質を持っています。
この3つはよく似た構文を持ちながらも振る舞いがまったく異なるため、混乱しがちです。

それぞれの特徴・ユースケース・ポイントを解説します。

mergeMap

並列実行(最も自由だが制御が難しい)

特徴

  • すべての inner Observable を即座に subscribe
  • 実行順序は保証されない
  • 非同期処理を並列実行したいときに使う

ユースケース

  • 複数APIの同時実行
  • ユーザーの操作を漏れなく処理
import { of } from 'rxjs';
import { delay, mergeMap } from 'rxjs/operators';

of('A', 'B', 'C').pipe(
  mergeMap(value =>
    of(`done: ${value}`).pipe(delay(1000))
  )
).subscribe(console.log);

// 出力(約1秒後)
// done: A
// done: B
// done: C
// 順番は保証されません(環境やタイミングにより done: B → A → C などもあり得ます)

ポイント

  • A, B, C のそれぞれの非同期処理が同時に開始される
  • delay(1000) によりそれぞれが 1 秒後に完了
  • 処理が並列のためほぼ同時に全て出力される

concatMap

順序保証(処理は1つずつ)

特徴

  • inner Observable の完了を待ってから次を実行
  • 順番を保証する
  • 並列性はなく、直列処理

ユースケース

  • 処理に順序が必要なAPI呼び出し
  • キュー処理など、1つずつ確実に処理したいとき
import { of } from 'rxjs';
import { delay, concatMap } from 'rxjs/operators';

of('A', 'B', 'C').pipe(
  concatMap(value =>
    of(`done: ${value}`).pipe(delay(1000))
  )
).subscribe(console.log);

// 出力
// (done: A) ← 1秒後に出力
// (done: B) ← さらに1秒後(2秒時点)
// (done: C) ← さらに1秒後(3秒時点)

ポイント

  • 各値が 順番に処理され、完了するまで次の処理は始まらない
  • delay(1000) により1件1秒なので、全体で約3秒かかる
  • 順序が非常に重要な処理(例:ログ記録、順次API実行など)に適している

switchMap

最新だけ残す(キャンセル可能)

特徴

  • 前の処理をキャンセルして、最新の Observable のみ実行
  • 最も UX 向け
  • 古いリクエストをキャンセルしたいときに便利

ユースケース

  • 検索バーのリアルタイム補完
  • ボタン連打などの 最新操作のみ反映
import { of } from 'rxjs';
import { delay, switchMap } from 'rxjs/operators';

of('A', 'B', 'C').pipe(
  switchMap(value =>
    of(`done ${value}`).pipe(delay(1000))
  )
).subscribe(console.log);

// 出力(約1秒後)
// done C

補足

  • of('A', 'B', 'C') は 即座に連続で値を流す
  • switchMap は、毎回新しい Observable を生成し、前のObservableはキャンセル
  • 各処理は delay(1000) によって1秒後に出力される予定
  • しかし次の値がすぐ来るため、前のObservableは完了せずにキャンセルされる
  • 最後の C だけは、後続がないためキャンセルされず完了 → 出力される

もっと分かりやすく表すとこのような流れです

switchMap(A)  →  キャンセルされる
switchMap(B)  →  キャンセルされる
switchMap(C)  →  ✅ 出力される(後続がない)

ポイント

  • switchMap は、常に最新のイベントにのみ反応する
  • 遅い非同期処理を抱えていると、途中でキャンセルされて出力されないケースが多い
  • UIの検索欄やボタン連打対策に最適

📌 switchMap の最大の強みは「非同期処理のキャンセル性」です。
Promiseasync/await だと一度始まった処理は、たとえ新しい入力が来ても止められず、完了を待つしかありません。
そのため、たとえばユーザーがボタンを連打したり、検索を連続で打ち込んだ場合に不要なリクエストもすべて実行されてしまうリスクがあります。

switchMapPromiseasync/await にはないRxJS特有の利点であり、リアクティブなアプリケーション設計において非常に重要な特性です。

振る舞い比較表

オペレータ 並列実行 処理順序保証 キャンセル機能 主な用途
mergeMap 並列実行が必要なAPI
concatMap 順序付きの直列API処理
switchMap ユーザー操作など最新の値だけ処理

オペレータの使い分けガイド

  • 並列で一気に処理したいmergeMap
    例:データ一覧に対する一括取得処理など

  • 順番通りに一つずつ処理したいconcatMap
    例:ログを順番に保存する、メッセージ送信など

  • ユーザー操作で「最新だけを処理したい」switchMap
    例: 検索バー、ボタン連打、リアルタイムリクエスト

まとめ

mergeMap, concatMap, switchMap はよく似ていますが、選択を誤るとバグやUX低下の原因になります。
それぞれの動作特性を理解し、「いつ何を使うか」を判断できるようになることで、RxJSの力を最大限に活かせるようになります。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?