Как обработать ошибки в Observable?angular-42

Обработка ошибок — критически важная часть работы с Observable. Рассмотрим различные подходы и лучшие практики.

1. Базовый обработчик ошибок в subscribe

Самый простой способ — обработка во втором аргументе subscribe:

someObservable.subscribe(
  data => console.log('Данные:', data),
  error => console.error('Ошибка:', error)
);

Особенности:

  • Прерывает поток при ошибке
  • Подходит для простых случаев
  • Не рекомендуется для сложной логики обработки ошибок

2. Оператор catchError

Позволяет перехватить ошибку и продолжить поток:

import { catchError } from 'rxjs/operators';

someObservable.pipe(
  catchError(error => {
    console.error('Ошибка:', error);
    // Возвращаем fallback значение или новый Observable
    return of({ fallback: true });
  })
).subscribe(data => console.log('Результат:', data));

Ключевые моменты:

  • Должен возвращать новый Observable
  • Позволяет продолжить поток после ошибки
  • Часто используется с HTTP-запросами

3. Retry логика при ошибках

Операторы для повторных попыток:

retry - повторяет попытку n раз

import { retry } from 'rxjs/operators';

someObservable.pipe(
  retry(3) // 3 попытки перед ошибкой
).subscribe(...);

retryWhen - более гибкий вариант

import { retryWhen, delay, take } from 'rxjs/operators';

someObservable.pipe(
  retryWhen(errors => errors.pipe(
    delay(1000), // задержка 1 сек
    take(3)      // максимум 3 попытки
  )
).subscribe(...);

4. Глобальный обработчик ошибок

Для централизованной обработки можно использовать:

import { ErrorHandler } from '@angular/core';

@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
  handleError(error: any) {
    // Логирование, отправка в сервис мониторинга и т.д.
    console.error('Global error:', error);
  }
}

И зарегистрировать в провайдерах модуля:

{ provide: ErrorHandler, useClass: GlobalErrorHandler }

5. Обработка ошибок HTTP-запросов

Специфические подходы для HTTP:

this.http.get('/api/data').pipe(
  catchError(error => {
    if (error.status === 404) {
      return of(null); // Обработка 404
    }
    if (error.status === 500) {
      // Логирование и перенаправление
      this.router.navigate(['/error']);
      return throwError(error);
    }
    return throwError(error);
  })
).subscribe(...);

6. Tap для side-эффектов без прерывания потока

import { tap } from 'rxjs/operators';

someObservable.pipe(
  tap({
    next: () => {},
    error: (err) => console.error('Ошибка в tap:', err)
  })
).subscribe(...);

7. Finalize для выполнения кода при завершении

import { finalize } from 'rxjs/operators';

someObservable.pipe(
  finalize(() => {
    // Выполнится в любом случае - при успехе или ошибке
    this.loading = false;
  })
).subscribe(...);

Лучшие практики обработки ошибок

  1. Не игнорируйте ошибки - всегда обрабатывайте явно
  2. Логируйте ошибки - в консоль и/или на сервер
  3. Пользовательский интерфейс - показывайте понятные сообщения
  4. Типизация ошибок - создайте свои Error классы
  5. Тестирование - проверяйте обработку ошибок в тестах

Резюмируем

Основные способы обработки:

  • subscribe error handler - для простых случаев
  • catchError - основной оператор для перехвата ошибок
  • retry/retryWhen - для повторных попыток
  • Глобальная обработка - через ErrorHandler
  • HTTP-специфичная - проверка статусов ошибок

Правильная обработка ошибок делает приложение:

  • Более стабильным
  • Удобным для пользователя
  • Проще в отладке