Back

Понимание типов ошибок и сообщений в JavaScript

Понимание типов ошибок и сообщений в JavaScript

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

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

  • Ошибки JavaScript — это структурированные объекты со свойствами name и message, которые предоставляют конкретную информацию о проблемах в коде
  • Существует восемь встроенных типов ошибок: SyntaxError, ReferenceError, TypeError, RangeError, URIError, EvalError, AggregateError и InternalError
  • Правильная обработка исключений с помощью блоков try-catch и пользовательских классов ошибок повышает надёжность приложения
  • Глобальные обработчики ошибок и инструменты отладки браузера необходимы для отслеживания ошибок в продакшене

Что такое ошибки JavaScript?

Ошибки JavaScript — это объекты, которые представляют проблемы, возникающие во время выполнения кода. Каждая ошибка содержит свойство name, идентифицирующее её тип, и свойство message, описывающее, что пошло не так. Это не случайные сбои — это структурированная обратная связь о конкретных проблемах в вашем коде.

Восемь встроенных типов ошибок

SyntaxError: нарушение правил

SyntaxError возникает, когда JavaScript не может разобрать ваш код из-за недопустимого синтаксиса. Интерпретатор останавливается ещё до начала выполнения.

// Missing closing parenthesis
console.log("Hello World");
// SyntaxError: missing ) after argument list

// Invalid JSON parsing
JSON.parse("{'invalid': 'json'}");
// SyntaxError: Unexpected token ' in JSON at position 1

Распространённые причины включают отсутствующие скобки, незакрытые строки или неправильно сформированный JSON. Эти ошибки полностью предотвращают выполнение вашего кода.

ReferenceError: использование неопределённого

ReferenceError возникает, когда вы пытаетесь обратиться к переменной, которая не существует в текущей области видимости.

console.log(userName);
// ReferenceError: userName is not defined

function greet() {
  let message = "Hello";
}
greet();
console.log(message);
// ReferenceError: message is not defined

Обычно это результат опечаток, обращения к переменным до их объявления или путаницы с областями видимости.

TypeError: операции с неправильным типом

TypeError возникает, когда вы выполняете операцию с несовместимым типом — например, вызываете не-функцию или обращаетесь к свойствам null или undefined.

const num = 42;
num();
// TypeError: num is not a function

const user = null;
console.log(user.name);
// TypeError: Cannot read properties of null (reading 'name')

Это одни из самых распространённых ошибок времени выполнения в JavaScript-приложениях.

RangeError: выход за границы

RangeError сигнализирует, что значение превышает допустимый диапазон.

const arr = new Array(-1);
// RangeError: Invalid array length

const num = 1;
num.toPrecision(101);
// RangeError: toPrecision() argument must be between 1 and 100

Обращайте внимание на эти ошибки при работе с конструкторами массивов, методами чисел или рекурсивными функциями, превышающими стек вызовов.

URIError: неправильно сформированные URI

URIError появляется, когда функции кодирования или декодирования URI получают недопустимые параметры.

decodeURIComponent('%');
// URIError: URI malformed

encodeURI('\uD800');
// URIError: URI malformed

Эти ошибки возникают при обработке URL со специальными символами или неполным процентным кодированием.

EvalError: проблемы с eval()

Хотя EvalError существует в спецификации, современный JavaScript не генерирует его. Он сохранён для обратной совместимости. Исторически проблемы с eval() вызывали этот тип ошибки.

AggregateError: множественные сбои

AggregateError объединяет несколько ошибок в один объект, что особенно полезно при работе с Promise.any().

Promise.any([
  Promise.reject(new Error("First failure")),
  Promise.reject(new Error("Second failure"))
]).catch(err => {
  console.log(err instanceof AggregateError); // true
  console.log(err.errors); // Array of individual errors
});

InternalError: ограничения движка

InternalError (нестандартная, специфичная для Firefox) возникает, когда движок JavaScript достигает внутренних ограничений.

function recursiveFunction() {
  recursiveFunction();
}
recursiveFunction();
// InternalError: too much recursion (Firefox)
// RangeError: Maximum call stack size exceeded (Chrome)

Обработка исключений с помощью try…catch

JavaScript предоставляет структурированную обработку исключений через операторы try, catch, finally и throw.

try {
  // Code that might throw an error
  const data = JSON.parse(userInput);
  processData(data);
} catch (error) {
  if (error instanceof SyntaxError) {
    console.error("Invalid JSON format:", error.message);
  } else if (error instanceof TypeError) {
    console.error("Data processing error:", error.message);
  } else {
    // Re-throw unknown errors
    throw error;
  }
} finally {
  // Cleanup code runs regardless
  closeConnections();
}

Оператор throw создаёт пользовательские ошибки:

function validateAge(age) {
  if (age < 0) {
    throw new RangeError("Age cannot be negative");
  }
  if (typeof age !== 'number') {
    throw new TypeError("Age must be a number");
  }
  return age;
}

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

Используйте конкретные типы ошибок при генерации пользовательских ошибок. Вместо общих объектов Error генерируйте TypeError для проблем с типами или RangeError для нарушений границ.

Обрабатывайте ошибки на правильном уровне. Не оборачивайте каждую функцию в try-catch. Обрабатывайте ошибки там, где вы можете осмысленно на них отреагировать.

Сохраняйте контекст ошибки при повторной генерации:

try {
  riskyOperation();
} catch (error) {
  // Add context without losing original stack trace
  error.message = `Failed during user ${userId} operation: ${error.message}`;
  throw error;
}

Создавайте пользовательские классы ошибок для проблем, специфичных для предметной области:

class ValidationError extends Error {
  constructor(field, value) {
    super(`Invalid value for ${field}: ${value}`);
    this.name = 'ValidationError';
    this.field = field;
    this.value = value;
  }
}

Эффективная отладка ошибок JavaScript

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

Для продакшен-приложений реализуйте глобальные обработчики ошибок:

window.addEventListener('error', (event) => {
  console.error('Global error:', event.error);
  // Send to error tracking service
});

window.addEventListener('unhandledrejection', (event) => {
  console.error('Unhandled promise rejection:', event.reason);
});

Заключение

Понимание типов ошибок JavaScript превращает отладку из угадывания в систематическое решение проблем. Каждый тип ошибки — от SyntaxError до AggregateError — точно сообщает вам, что пошло не так и где искать. В сочетании с правильной обработкой исключений с использованием блоков try-catch и осмысленными сообщениями об ошибках вы можете создавать приложения, которые корректно обрабатывают сбои и предоставляют чёткую обратную связь при возникновении проблем. Ключ не в том, чтобы избегать всех ошибок — а в том, чтобы грамотно обрабатывать их, когда они возникают.

Часто задаваемые вопросы

Генерация ошибки немедленно останавливает выполнение и всплывает вверх до тех пор, пока не будет поймана блоком try-catch или не приведёт к краху программы. Возврат значения ошибки сохраняет поток выполнения, но требует явной проверки. Используйте throw для исключительных случаев, которые должны прервать нормальный поток, и возвращайте значения для ожидаемых сбоев.

Используйте window.addEventListener с событием unhandledrejection для глобального перехвата отклонённых промисов. Для асинхронных функций оборачивайте их в блоки try-catch или присоединяйте обработчики catch к возвращаемым промисам. Это предотвращает тихие сбои и помогает отслеживать ошибки в продакшене.

Каждый движок JavaScript реализует сообщения об ошибках по-своему, следуя одной и той же спецификации ECMAScript для типов ошибок. Chrome V8, Firefox SpiderMonkey и Safari JavaScriptCore могут формулировать сообщения уникально, но тип ошибки и поведение остаются согласованными.

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay