Реализовать живой поиск: пользователь печатает в поле, а мы дёргаем API. Нужно не спамить запросами на каждую букву, не повторять запрос при том же тексте и не показывать устаревшие ответы.
Решение
Оптимальное решение
const results$ = fromEvent(input, 'input').pipe( map((e) => (e.target as HTMLInputElement).value.trim()), debounceTime(300), // ждём паузу в наборе — не бьём на каждую букву distinctUntilChanged(), // игнорируем, если текст не изменился filter((q) => q.length >= 2), // не ищем по слишком коротким запросам switchMap((q) => this.api.search(q)), // отменяем предыдущий запрос);results$.subscribe((items) => this.render(items));
Роль каждого оператора
debounceTime(300) — эмитит значение, только если 300мс не было нового ввода. Гасит шквал событий при быстром наборе.
distinctUntilChanged() — пропускает повтор, если строка не изменилась (например, ввёл и стёр символ).
filter(q => q.length >= 2) — отсекает слишком короткие/пустые запросы.
switchMap — на новый запрос отменяет предыдущий незавершённый. Именно то, что нужно для поиска: важен только ответ на последний ввод, гонки исключены.
Почему именно switchMap, а не mergeMap
С mergeMap запросы идут параллельно и ответы могут прийти не по порядку — медленный ответ на старый запрос перезапишет свежий результат (race condition). switchMap отменяет устаревшее и всегда показывает актуальное.