BACK
Уроки35. catchError внутри switchMap
Уроки · 35

35. catchError внутри switchMap

Где ставить catchError — критически важно

Из предыдущего урока вы знаете: ошибка летит вверх по pipe, пока не встретит catchError. Но есть тонкость, которую очень важно понимать в реальных приложениях:

Когда ошибка перехвачена, поток в этой точке завершается. Внешний источник, ниже которого был перехват, продолжает жить. Внешний источник, выше которого был перехват, — тоже мёртв.

Два варианта

// ПЛОХО: catchError снаружи — убивает поле поиска
query$.pipe(
  switchMap(q => fakeRequest(q)),
  catchError(...)   // после первой ошибки query$ мёртв
)

// ХОРОШО: catchError внутри switchMap — падает только один запрос
query$.pipe(
  switchMap(q => fakeRequest(q).pipe(
    catchError(...)  // ловим тут — внешний query$ жив
  ))
)

Реальный сценарий

Поле живого поиска: пользователь ввёл странный запрос, сервер вернул ошибку. Если catchError снаружи — следующий ввод уже не сработает, поток мёртв. Если внутри — упал только один запрос, следующий ввод снова запустит switchMap.

Что нужно сделать

  1. Внутри функции, переданной в switchMap, в fakeRequest(query).pipe(...) добавьте catchError(error => of('Fallback: ' + query)).
  2. Заметьте: catchError стоит во внутреннем pipe, а не во внешнем.
  3. Ожидаемый вывод: Result: ok → Fallback: bad → Result: next. После провала bad поток жив и обрабатывает next.
Решение spoiler · click to reveal
const { from, of, throwError, switchMap, catchError } = Rx;

function fakeRequest(query) {
  if (query === 'bad') {
    return throwError(() => 'Request failed');
  }
  return of('Result: ' + query);
}

const query$ = from(['ok', 'bad', 'next']);

const result$ = query$.pipe(
  switchMap(query => {
    return fakeRequest(query).pipe(
      catchError(error => of('Fallback: ' + query))
    );
  })
);

result$.subscribe(value => console.log(value));
script.ts // TypeScript
CONSOLE · Console Output
Нажмите на запуск, чтобы увидеть результат...