PassFront
  1. PassFront
  2. База знаний
  3. Signals и RxJS

Чем отличаются операторы switchMap, mergeMap, concatMap и exhaustMap в RxJS?

Signals и RxJS

Все четыре — операторы «высшего порядка»: для каждого значения источника они запускают внутренний Observable (например, HTTP-запрос) и сводят результаты в один поток. Отличаются тем, что делать, пока предыдущий внутренний поток ещё не завершён.

switchMap — переключиться на новый

Отписывается от предыдущего внутреннего потока и берёт последний. Подходит для поиска по мере ввода и навигации: нужен только актуальный результат, устаревшие запросы отменяются.

search$.pipe(
  debounceTime(300),
  switchMap(q => this.http.get(`/api?q=${q}`)),
);

mergeMap — параллельно

Запускает все внутренние потоки одновременно, результаты приходят в порядке завершения. Подходит для независимых операций, где порядок не важен (отправка нескольких файлов). Может перегрузить сервер: у него есть параметр concurrent.

concatMap — по очереди

Ставит внутренние потоки в очередь и выполняет строго по порядку, каждый после завершения предыдущего. Подходит для операций, где важен порядок (последовательные записи, сохранение изменений).

exhaustMap — игнорировать, пока занят

Пока внутренний поток выполняется, новые значения источника игнорируются. Подходит для защиты от двойного клика: кнопка «Отправить», вход в систему.

click$.pipe(exhaustMap(() => this.http.post('/api/order', body)));

Сравнение

  • `switchMap` — Параллельность: отменяет предыдущий; Порядок результатов: актуальный; Что с новыми значениями: заменяют старые
  • `mergeMap` — Параллельность: да; Порядок результатов: по завершении; Что с новыми значениями: запускаются сразу
  • `concatMap` — Параллельность: нет; Порядок результатов: исходный; Что с новыми значениями: ждут в очереди
  • `exhaustMap` — Параллельность: нет; Порядок результатов: исходный; Что с новыми значениями: отбрасываются

Коротко для собеседования

switchMap — только последнее (поиск), mergeMap — всё параллельно, concatMap — по очереди с сохранением порядка, exhaustMap — игнорирует новые, пока идёт текущее (защита от повторных кликов).

Другие вопросы раздела