Отладка JavaScript: как находить и исправлять ошибки

Раздел: Программирование -> Отладка ошибок

Методы отладки JavaScript

Ошибки в JavaScript - неизбежная часть разработки. Давайте рассмотрим основные способы их обнаружения и исправления, от простых логов до продвинутых инструментов.

Как найти ошибку с помощью DevTools?

Самый эффективный способ отладки - использование инструментов разработчика браузера (Chrome DevTools, Firefox Developer Tools и другие).

function multiply(a, b) {
  debugger;
  return a * b;
}
console.log(multiply(2, '3'));

Js ошибка (ошибка javascript)

Шаги: Откройте DevTools (F12), перейдите на вкладку Sources, найдите файл с кодом, поставьте breakpoint на строке debugger или щёлкните по номеру строки. Выполнение остановится, и вы увидите Scope (локальные переменные) и Call Stack (стек вызовов). Переменная a равна 2, b равно '3' - результат будет строкой '23', а не числом 6.

Проблема: Breakpoint может не сработать, если код загружен динамически (через eval или import). Для таких случаев используйте ключевое слово debugger прямо в коде. Также при использовании обфусцированного или минифицированного кода включите Source Maps.

Как быстро вывести значения переменных?

Самый простой способ - добавить console.log в нужные места.

const result = fetchData();
console.log('Результат:', result);
if (result.length > 0) {
  console.table(result[0]); // вывод объекта в виде таблицы
} else {
  console.warn('Пустой ответ');
}

Цель: быстро проверить значения без остановки выполнения. Плюсы - простота, минусы - засорение консоли, необходимость удалять логи перед продакшеном.

Проблема: Если логов много, сложно найти нужный. Используйте console.group для группировки или заведите специальную функцию-логгер.

Как предотвратить падение скрипта при ошибке?

Конструкция try/catch позволяет обработать исключения и продолжить выполнение.

try {
  JSON.parse('невалидный json');
} catch (e) {
  console.warn('Ошибка парсинга:', e.message);
  // можно предпринять альтернативные действия
}

Цель: обернуть потенциально опасный код (парсинг, работа с API, математические операции) и корректно обработать ошибку. catch получает объект ошибки с полями name, message, stack.

Проблема: try/catch не ловит асинхронные ошибки (setTimeout, Promise, callbacks). Для промисов используйте .catch() или try/catch внутри async функции. Также не стоит злоупотреблять - каждая обёртка добавляет накладные расходы.

Как отловить ошибку в Promise?

Для асинхронных операций (fetch, Promise) используйте .catch() или try/catch внутри async функций.

async function getData() {
  try {
    const response = await fetch('/api');
    const data = await response.json();
  } catch (err) {
    console.error('Сетевая ошибка:', err.message);
  }
}

Цель: обработка ошибок в цепочках промисов. Если не добавить .catch(), ошибка станет unhandled rejection и может привести к неожиданному поведению.

Проблема: Легко забыть добавить catch. В Node.js глобальный обработчик process.on('unhandledRejection', ...) перехватит такие ошибки. В браузере они выводятся в консоль, но не прерывают выполнение.

Как избежать ошибок до выполнения кода?

Статические анализаторы (линтеры), такие как ESLint, находят потенциальные ошибки на этапе написания кода.

// .eslintrc.json
{
  "rules": {
    "no-undef": "error",
    "no-unused-vars": "warn"
  }
}

Команда: npx eslint app.js выведет все найденные проблемы. Линтер проверяет синтаксис, неиспользуемые переменные, опасные конструкции.

Цель: предотвратить опечатки, использование необъявленных переменных, и т.д. Интегрируйте линтер в редактор (VSCode) и CI/CD.

Проблема: Линтер не обнаруживает логические ошибки и проблемы времени выполнения (например, undefined is not a function). Настраивайте правила под конкретный проект, чтобы избежать ложных срабатываний.

Расширенные примеры с типичными ошибками и способами их отладки.

Пример
// Пример 1: ReferenceError - необъявленная переменная
function test() {
  console.log(notDefined);
}
test();
Uncaught ReferenceError: notDefined is not defined
    at test (app.js:2)
    at app.js:5

Ошибка говорит об отсутствии переменной. Решение: объявить через let/const или проверить через typeof.

Пример
// Пример 2: TypeError - чтение свойства у undefined
const obj = {};
console.log(obj.data.name);
Uncaught TypeError: Cannot read properties of undefined (reading 'name')
    at app.js:2

Решение: использовать опциональную цепочку obj.data?.name или проверку if (obj.data).

Пример
// Пример 3: Необработанный промис (unhandled rejection)
async function fail() {
  throw new Error('Async fail');
}
Promise.resolve().then(() => fail()).then(() => console.log('success'));
Uncaught (in promise) Error: Async fail
    at fail (app.js:2)
    at app.js:4

Ошибка не перехвачена. Добавьте .catch(err => console.error(err)) в конец цепочки.

Пример
// Пример 4: Использование console.trace() для отслеживания стека
function one() { two(); }
function two() { three(); }
function three() { console.trace('Вызвана three'); }
one();
Вызвана three
console.trace @ app.js:4
three @ app.js:4
two @ app.js:3
one @ app.js:2
(anonymous) @ app.js:6

Полезно для понимания последовательности вызовов, особенно при рекурсии или замыканиях.

Пример
// Пример 5: Глобальный обработчик unhandledRejection в Node.js
process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled Rejection at:', promise, 'reason:', reason);
});
async function fail() { throw new Error('error'); }
fail(); // без .catch()
Unhandled Rejection at: Promise { <rejected> Error: error } reason: Error: error

Это защитный механизм на продакшн-сервере. Все необработанные промисы будут зафиксированы.

Ошибка JavaScript - comments

En
Js ошибка (javascript)