Throw exceptions in javascript

throw

The throw statement throws a user-defined exception. Execution of the current function will stop (the statements after throw won’t be executed), and control will be passed to the first catch block in the call stack. If no catch block exists among caller functions, the program will terminate.

Try it

Syntax

Description

The throw statement is valid in all contexts where statements can be used. Its execution generates an exception that penetrates through the call stack. For more information on error bubbling and handling, see Control flow and error handling.

The throw keyword can be followed by any kind of expression, for example:

throw error; // Throws a previously defined value (e.g. within a catch block) throw new Error("Required"); // Throws a new Error object 

In practice, the exception you throw should always be an Error object or an instance of an Error subclass, such as RangeError . This is because code that catches the error may expect certain properties, such as message , to be present on the caught value. For example, web APIs typically throw DOMException instances, which inherit from Error.prototype .

Automatic semicolon insertion

The syntax forbids line terminators between the throw keyword and the expression to be thrown.

The code above is transformed by automatic semicolon insertion (ASI) into:

Читайте также:  Питон таймер выполнения программы

This is invalid code, because unlike return , throw must be followed by an expression.

To avoid this problem (to prevent ASI), you could use parentheses:

Examples

Throwing a user-defined error

This example defines a function that throws a TypeError if the input is not of the expected type.

function isNumeric(x)  return ["number", "bigint"].includes(typeof x); > function sum(. values)  if (!values.every(isNumeric))  throw new TypeError("Can only add numbers"); > return values.reduce((a, b) => a + b); > console.log(sum(1, 2, 3)); // 6 try  sum("1", "2"); > catch (e)  console.error(e); // TypeError: Can only add numbers > 

Throwing an existing object

This example calls a callback-based async function, and throws an error if the callback receives an error.

readFile("foo.txt", (err, data) =>  if (err)  throw err; > console.log(data); >); 

Errors thrown this way are not catchable by the caller and will cause the program to crash unless (a) the readFile function itself catches the error, or (b) the program is running in a context that catches top-level errors. You can handle errors more naturally by using the Promise() constructor.

function readFilePromise(path)  return new Promise((resolve, reject) =>  readFile(path, (err, data) =>  if (err)  reject(err); > resolve(data); >); >); > try  const data = await readFilePromise("foo.txt"); console.log(data); > catch (err)  console.error(err); > 

Specifications

Browser compatibility

BCD tables only load in the browser

See also

Found a content problem with this page?

This page was last modified on Jun 19, 2023 by MDN contributors.

Your blueprint for a better internet.

Источник

Перехват ошибок, «try..catch»

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

Более новая информация по этой теме находится на странице https://learn.javascript.ru/try-catch.

Как бы мы хорошо ни программировали, в коде бывают ошибки. Или, как их иначе называют, «исключительные ситуации» (исключения).

Обычно скрипт при ошибке, как говорят, «падает», с выводом ошибки в консоль.

Но бывают случаи, когда нам хотелось бы как-то контролировать ситуацию, чтобы скрипт не просто «упал», а сделал что-то разумное.

Для этого в JavaScript есть замечательная конструкция try..catch .

Конструкция try…catch

Конструкция try..catch состоит из двух основных блоков: try , и затем catch :

  1. Выполняется код внутри блока try .
  2. Если в нём ошибок нет, то блок catch(err) игнорируется, то есть выполнение доходит до конца try и потом прыгает через catch .
  3. Если в нём возникнет ошибка, то выполнение try на ней прерывается, и управление прыгает в начало блока catch(err) . При этом переменная err (можно выбрать и другое название) будет содержать объект ошибки с подробной информацией о произошедшем.

Таким образом, при ошибке в try скрипт не «падает», и мы получаем возможность обработать ошибку внутри catch .

Посмотрим это на примерах.

    Пример без ошибок: при запуске сработают alert (1) и (2) :

try < alert('Начало блока try'); // (1) catch(e) < alert('Блок catch не получит управление, так как нет ошибок'); // (3) >alert("Потом код продолжит выполнение. ");
try < alert('Начало блока try'); // (1) catch(e) < alert('Ошибка ' + e.name + ":" + e.message + "\n" + e.stack); // (3) alert("Потом код продолжит выполнение. ");

Если грубо нарушена структура кода, например не закрыта фигурная скобка или где-то стоит лишняя запятая, то никакой try..catch здесь не поможет. Такие ошибки называются синтаксическими, интерпретатор не может понять такой код.

Здесь же мы рассматриваем ошибки семантические, то есть происходящие в корректном коде, в процессе выполнения.

Ошибку, которая произойдёт в коде, запланированном «на будущее», например в setTimeout , try..catch не поймает:

На момент запуска функции, назначенной через setTimeout , этот код уже завершится, интерпретатор выйдет из блока try..catch .

Чтобы поймать ошибку внутри функции из setTimeout , и try..catch должен быть в той же функции.

Объект ошибки

В примере выше мы видим объект ошибки. У него есть три основных свойства:

name Тип ошибки. Например, при обращении к несуществующей переменной: "ReferenceError" . message Текстовое сообщение о деталях ошибки. stack Везде, кроме IE8-, есть также свойство stack , которое содержит строку с информацией о последовательности вызовов, которая привела к ошибке.

В зависимости от браузера у него могут быть и дополнительные свойства, см. Error в MDN и Error в MSDN.

Пример использования

В JavaScript есть встроенный метод JSON.parse(str), который используется для чтения JavaScript-объектов (и не только) из строки.

Обычно он используется для того, чтобы обрабатывать данные, полученные по сети, с сервера или из другого источника.

Мы получаем их и вызываем метод JSON.parse , вот так:

var data = ''; // строка с данными, полученная с сервера var user = JSON.parse(data); // преобразовали строку в объект // теперь user -- это JS-объект с данными из строки alert( user.name ); // Вася alert( user.age ); // 30

Более детально формат JSON разобран в главе Формат JSON, метод toJSON.

В случае, если данные некорректны, JSON.parse генерирует ошибку, то есть скрипт «упадёт».

Устроит ли нас такое поведение? Конечно нет!

Получается, что если вдруг что-то не так с данными, то посетитель никогда (если, конечно, не откроет консоль) об этом не узнает.

А люди очень-очень не любят, когда что-то «просто падает», без всякого объявления об ошибке.

Бывают ситуации, когда без try..catch не обойтись, это – одна из таких.

Используем try..catch , чтобы обработать некорректный ответ:

var data = "Has Error"; // в данных ошибка try < var user = JSON.parse(data); // catch (e) < // . выполнится catch alert( "Извините, в данных ошибка, мы попробуем получить их ещё раз" ); alert( e.name ); alert( e.message ); >

Здесь в alert только выводится сообщение, но область применения гораздо шире: можно повторять запрос, можно предлагать посетителю использовать альтернативный способ, можно отсылать информацию об ошибке на сервер… Свобода действий.

Генерация своих ошибок

Представим на минуту, что данные являются корректным JSON… Но в этом объекте нет нужного свойства name :

var data = '< "age": 30 >'; // данные неполны try < var user = JSON.parse(data); // catch (e) < // не выполнится alert( "Извините, в данных ошибка" ); >

Вызов JSON.parse выполнится без ошибок, но ошибка в данных есть. И, так как свойство name обязательно должно быть, то для нас это такие же некорректные данные, как и "Has Error" .

Для того, чтобы унифицировать и объединить обработку ошибок парсинга и ошибок в структуре, мы воспользуемся оператором throw .

Оператор throw

Оператор throw генерирует ошибку.

Технически в качестве объекта ошибки можно передать что угодно, это может быть даже не объект, а число или строка, но всё же лучше, чтобы это был объект, желательно – совместимый со стандартным, то есть чтобы у него были как минимум свойства name и message .

В качестве конструктора ошибок можно использовать встроенный конструктор: new Error(message) или любой другой.

В JavaScript встроен ряд конструкторов для стандартных ошибок: SyntaxError , ReferenceError , RangeError и некоторые другие. Можно использовать и их, но только чтобы не было путаницы.

В данном случае мы используем конструктор new SyntaxError(message) . Он создаёт ошибку того же типа, что и JSON.parse .

var data = '< "age": 30 >'; // данные неполны try < var user = JSON.parse(data); // alert( user.name ); > catch (e)

Получилось, что блок catch – единое место для обработки ошибок во всех случаях: когда ошибка выявляется при JSON.parse или позже.

Проброс исключения

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

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

Блок catch в нашем примере предназначен для обработки ошибок, возникающих при некорректных данных. Если же в него попала какая-то другая ошибка, то вывод сообщения о «некорректных данных» будет дезинформацией посетителя.

Ошибку, о которой catch не знает, он не должен обрабатывать.

Такая техника называется «проброс исключения»: в catch(e) мы анализируем объект ошибки, и если он нам не подходит, то делаем throw e .

При этом ошибка «выпадает» из try..catch наружу. Далее она может быть поймана либо внешним блоком try..catch (если есть), либо «повалит» скрипт.

В примере ниже catch обрабатывает только ошибки SyntaxError , а остальные – выбрасывает дальше:

var data = '< "name": "Вася", "age": 30 >'; // данные корректны try < var user = JSON.parse(data); if (!user.name) < throw new SyntaxError("Ошибка в данных"); >blabla(); // произошла непредусмотренная ошибка alert( user.name ); > catch (e) < if (e.name == "SyntaxError") < alert( "Извините, в данных ошибка" ); >else < throw e; >>

Заметим, что ошибка, которая возникла внутри блока catch , «выпадает» наружу, как если бы была в обычном коде.

В следующем примере такие ошибки обрабатываются ещё одним, «более внешним» try..catch :

function readData() < var data = '< "name": "Вася", "age": 30 >'; try < // . blabla(); // ошибка! >catch (e) < // . if (e.name != 'SyntaxError') < throw e; // пробрасываем >> > try < readData(); >catch (e) < alert( "Поймал во внешнем catch: " + e ); // ловим >

В примере выше try..catch внутри readData умеет обрабатывать только SyntaxError , а внешний – все ошибки.

Без внешнего проброшенная ошибка «вывалилась» бы в консоль с остановкой скрипта.

Оборачивание исключений

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

Цель функции readData в примере выше – прочитать данные. При чтении могут возникать разные ошибки, не только SyntaxError , но и, возможно, к примеру URIError (неправильное применение функций работы с URI) да и другие.

Код, который вызвал readData , хотел бы иметь либо результат, либо информацию об ошибке.

При этом очень важным является вопрос: обязан ли этот внешний код знать о всевозможных типах ошибок, которые могут возникать при чтении данных, и уметь перехватывать их?

Обычно внешний код хотел бы работать «на уровень выше», и получать либо результат, либо «ошибку чтения данных», при этом какая именно ошибка произошла – ему неважно. Ну, или, если будет важно, то хотелось бы иметь возможность это узнать, но обычно не требуется.

Это важнейший общий подход к проектированию – каждый участок функциональности должен получать информацию на том уровне, который ей необходим.

Мы его видим везде в грамотно построенном коде, но не всегда отдаём себе в этом отчёт.

В данном случае, если при чтении данных происходит ошибка, то мы будем генерировать её в виде объекта ReadError , с соответствующим сообщением. А «исходную» ошибку на всякий случай тоже сохраним, присвоим в свойство cause (англ. – причина).

function ReadError(message, cause) < this.message = message; this.cause = cause; this.name = 'ReadError'; this.stack = cause.stack; >function readData() < var data = '< bad data >'; try < // . JSON.parse(data); // . >catch (e) < // . if (e.name == 'URIError') < throw new ReadError("Ошибка в URI", e); >else if (e.name == 'SyntaxError') < throw new ReadError("Синтаксическая ошибка в данных", e); >else < throw e; // пробрасываем >> > try < readData(); >catch (e) < if (e.name == 'ReadError') < alert( e.message ); alert( e.cause ); // оригинальная ошибка-причина >else < throw e; >>

Этот подход называют «оборачиванием» исключения, поскольку мы берём ошибки «более низкого уровня» и «заворачиваем» их в ReadError , которая соответствует текущей задаче.

Секция finally

Конструкция try..catch может содержать ещё один блок: finally .

Выглядит этот расширенный синтаксис так:

Секция finally не обязательна, но если она есть, то она выполняется всегда:

Попробуйте запустить такой код?

Источник

Оцените статью