← Назад к вопросам

Можно ли поймать ошибку Promise?

1.7 Middle🔥 281 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Обработка ошибок в Promises

Да, можно и нужно ловить ошибки в Promise. Есть несколько способов, и каждый используется в зависимости от ситуации.

1. Метод .catch()

Классический способ - добавить обработчик ошибки через .catch():

Promise.resolve()
  .then(() => {
    throw new Error('Произошла ошибка!');
  })
  .catch((error) => {
    console.error('Поймали ошибку:', error.message);
  });

// Или с реальным запросом
fetch('/api/data')
  .then((response) => {
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .then((data) => {
    console.log('Данные получены:', data);
  })
  .catch((error) => {
    console.error('Ошибка:', error.message);
  });

2. try/catch с async/await

Модернизированный способ, который читать проще:

async function fetchData() {
  try {
    const response = await fetch('/api/data');
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    const data = await response.json();
    console.log('Данные:', data);
    return data;
  } catch (error) {
    console.error('Ошибка при загрузке:', error);
    // Можно пробросить ошибку дальше
    throw error;
  }
}

3. Цепочка .catch() обработчиков

Можно ловить разные типы ошибок на разных уровнях:

Promise.resolve()
  .then(() => fetchUser())
  .catch((error) => {
    console.error('Ошибка при получении пользователя:', error);
    // Можем вернуть значение по умолчанию
    return { id: 0, name: 'Guest' };
  })
  .then((user) => fetchUserPosts(user.id))
  .catch((error) => {
    console.error('Ошибка при получении постов:', error);
    return [];
  })
  .then((posts) => {
    console.log('Всё готово, посты:', posts);
  });

4. Promise.all() с обработкой ошибок

Когда выполняешь несколько промисов одновременно:

// Если хотя бы один Promise отклонится, весь Promise.all() падает
Promise.all([
  fetch('/api/users').then(r => r.json()),
  fetch('/api/posts').then(r => r.json()),
  fetch('/api/comments').then(r => r.json())
])
  .then(([users, posts, comments]) => {
    console.log('Все данные загружены');
  })
  .catch((error) => {
    console.error('Одна из запросов не удалась:', error);
  });

// Или с async/await
async function loadAllData() {
  try {
    const [users, posts, comments] = await Promise.all([
      fetch('/api/users').then(r => r.json()),
      fetch('/api/posts').then(r => r.json()),
      fetch('/api/comments').then(r => r.json())
    ]);
    return { users, posts, comments };
  } catch (error) {
    console.error('Ошибка при загрузке данных:', error);
    throw error;
  }
}

5. Promise.allSettled() - продолжить при ошибках

Если нужно выполнить все промисы, даже если некоторые упадут:

const promises = [
  fetch('/api/users').then(r => r.json()),
  fetch('/api/posts').then(r => r.json()),
  fetch('/api/broken').then(r => r.json()) // Эта упадёт
];

Promise.allSettled(promises)
  .then((results) => {
    results.forEach((result, index) => {
      if (result.status === 'fulfilled') {
        console.log(`Запрос ${index} успешен:`, result.value);
      } else {
        console.error(`Запрос ${index} упал:`, result.reason);
      }
    });
  });

// Вывод:
// Запрос 0 успешен: {users...}
// Запрос 1 успешен: {posts...}
// Запрос 2 упал: Error: 404 Not Found

6. finally() - очистка ресурсов

Выполняется в любом случае, успешно или с ошибкой:

let isLoading = true;

fetch('/api/data')
  .then((response) => response.json())
  .then((data) => {
    console.log('Данные:', data);
  })
  .catch((error) => {
    console.error('Ошибка:', error);
  })
  .finally(() => {
    isLoading = false;
    console.log('Загрузка завершена');
  });

7. Перехват необработанных ошибок Promise

Если ошибка не обработана, используй обработчик на уровне window:

// Обработка необработанных отклонений Promise
window.addEventListener('unhandledrejection', (event) => {
  console.error('Необработанное отклонение Promise:', event.reason);
  // event.preventDefault() - чтобы браузер не логировал ошибку
  event.preventDefault();
});

// Тестирование
Promise.reject(new Error('Я не обработана!'));
// Будет поймана обработчиком unhandledrejection

8. Практический пример с React компонентом

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let isMounted = true;

    const loadUser = async () => {
      try {
        setLoading(true);
        const response = await fetch(`/api/users/${userId}`);
        
        if (!response.ok) {
          throw new Error(`User not found: ${response.status}`);
        }
        
        const userData = await response.json();
        
        if (isMounted) {
          setUser(userData);
          setError(null);
        }
      } catch (err) {
        if (isMounted) {
          setError(err.message);
          setUser(null);
        }
      } finally {
        if (isMounted) {
          setLoading(false);
        }
      }
    };

    loadUser();

    // Cleanup функция
    return () => {
      isMounted = false;
    };
  }, [userId]);

  if (loading) return <div>Загрузка...</div>;
  if (error) return <div>Ошибка: {error}</div>;
  if (!user) return <div>Пользователь не найден</div>;

  return <div>Имя: {user.name}</div>;
}

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

  1. Всегда добавляй .catch() - не оставляй неловленные ошибки
  2. Используй async/await вместо цепочки .then() для читаемости
  3. Логируй ошибки - это поможет в отладке
  4. Показывай пользователю ошибку - если это пользовательское действие
  5. Используй finally() - для очистки (закрытие загрузочных индикаторов, спиннеров)
  6. Не игнорируй ошибки - даже если они неожиданные
  7. Разделяй обработку разных типов ошибок на разных уровнях

Обработка ошибок в Promises - это критически важная часть разработки надёжного и пользовательского приложения.