Learn JavaScript

try/catch в JavaScript: обработка ошибок

Ошибки в JavaScript бывают неизбежны: некорректные данные, нестабильная сеть, неожиданные состояния. try/catch - базовый инструмент, чтобы контролировать ошибки и не “ронять” весь сценарий.

Главное: try/catch ловит ошибки внутри блока try и в момент выполнения. Для асинхронных ошибок нужен await или обработка через Promise.

1) Базовая форма try/catch

try {
  const result = JSON.parse("{ bad json }");
  console.log(result);
} catch (e) {
  console.log(e.name);
  console.log(e.message);
}

Если внутри try будет ошибка, управление перейдет в catch.

2) Что ловит try/catch

Он ловит:

  • ошибки времени выполнения (ReferenceError, TypeError и т.д.)
  • ошибки, которые бросаются через throw

Пример:

try {
  const a = null;
  console.log(a.value);
} catch (e) {
  console.log(e.name); // "TypeError"
}

3) throw: выбросить ошибку вручную

throw используется, когда нужно явно остановить выполнение и сообщить об ошибке.

function parseJSON(text) {
  if (typeof text !== "string") {
    throw new TypeError("text must be a string");
  }

  return JSON.parse(text);
}

try {
  parseJSON(123);
} catch (e) {
  console.log(e.name);
  console.log(e.message);
}

4) finally: выполнится всегда

finally выполняется и при успехе, и при ошибке. Туда удобно помещать финальные действия: убрать индикатор загрузки, вернуть кнопку в активное состояние.

try {
  console.log("start");
  JSON.parse("{ bad json }");
} catch (e) {
  console.log("error");
} finally {
  console.log("finish");
}

5) try/catch не ловит ошибки Promise без await

Это частая ловушка. Ошибка в Promise появляется позже, и синхронный try/catch ее не поймает.

try {
  Promise.reject(new Error("Fail"));
} catch (e) {
  console.log("not caught");
}

Правильные варианты:

Вариант 1: catch у Promise

Promise.reject(new Error("Fail")).catch((e) => {
  console.log(e.message);
});

Вариант 2: await внутри try/catch

async function run() {
  try {
    await Promise.reject(new Error("Fail"));
  } catch (e) {
    console.log(e.message);
  }
}

run();

6) Обработка ошибок в async/await

Реальный шаблон: запрос, проверка статуса, парсинг JSON.

async function loadJSON(url) {
  const response = await fetch(url);

  if (!response.ok) {
    throw new Error("HTTP " + response.status);
  }

  return response.json();
}

async function run() {
  try {
    const data = await loadJSON("/api/data");
    console.log(data);
  } catch (e) {
    console.log(e.message);
  }
}

run();

7) Делать сообщение об ошибке понятным

Ошибку можно логировать полностью:

try {
  JSON.parse("{ bad json }");
} catch (e) {
  console.log(e);
}

А можно выводить только важное:

try {
  JSON.parse("{ bad json }");
} catch (e) {
  console.log(e.name + ": " + e.message);
}

8) Что лучше не делать: глотать ошибки молча

Если catch пустой, ошибка исчезнет и отладка станет сложнее.

try {
  JSON.parse("{ bad json }");
} catch (e) {}

Лучше хотя бы вывести сообщение:

try {
  JSON.parse("{ bad json }");
} catch (e) {
  console.log(e.message);
}

Что стоит запомнить

  • try/catch ловит ошибки только во время выполнения кода в try.
  • throw позволяет выбрасывать ошибки вручную.
  • finally выполняется всегда, удобен для финальных действий.
  • Для Promise try/catch работает только вместе с await.
  • В async/await типовой шаблон: try { await ... } catch { ... }.