Понимание типов ошибок и сообщений в 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)
Discover how at OpenReplay.com.
Обработка исключений с помощью 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.