Catch не ловит ошибки js

if (!city) {
      let fetchResult;
      try {
        const url = `https://ipinfo.io/json?token=${APIKEYS.ipinfo}`;
        fetchResult = await fetch(url)
      } catch (err) {
        console.log('hello');
        this.city = 'Minsk';
        return false;
      }

Почему в таком блоке не отлавливается ошибка возникающая при fetch?


  • Вопрос задан

    более трёх лет назад

  • 1196 просмотров

Вы какую ошибку пытаетесь отловить?
При 404 ошибке fetch все равно завершится доожным образом просто вернет код отличный от 200 и не OK
https://developer.mozilla.org/en-US/docs/Web/API/F…
https://developer.mozilla.org/en-US/docs/Web/API/F…

const url = `https://ipinfo.io/json`;
        fetch(url).then(response => {
          console.log(response.status, response.ok)
          if (response.ok) {
            response.json().then(data => {
            console.log(data)
            })
          }
        })

const url = `https://ipinfo.io/jsonson`;
        fetch(url).then(response => {
          console.log(response.status, response.ok)
          if (response.ok) {
            response.json().then(data => {
            console.log(data)
            })
          }
        })

Если бы fetch кидал ошибку, вы бы ее отловили

function some() {
  return Promise.reject("Hello")
}

async function f() {
  try {
    return await some();
  } catch (error) {
    console.log("Error", error)
  }

}

f().then(data => {
  console.log("Data", data)
});

Пригласить эксперта

Если хотите сахарно работать с запросами в trycatch стиле посмотрите на axios.
Он такой код как:

async getData() {
  try {
   const { data } = axios.get('/url') 
  }catch(e) {
    console.error(e)
  }
}

Обработает так как вы того ждете. Но сразу скажу, что в данном контексте он делает что-то вроде:

async getData() {
    try{
      const response = fetch('/url')
      if(response.status>= 400 && response.status<= 599) throw new Error(`Http exeption code: ${response.status}`)
    }catch(e){
      console.error(e)
    }
  }


  • Показать ещё
    Загружается…

04 июн. 2023, в 01:35

1500 руб./за проект

04 июн. 2023, в 01:25

40000 руб./за проект

03 июн. 2023, в 23:42

1500 руб./за проект

Минуточку внимания

For some reason this code gives me an uncaught exception error. It seems the catch block is not catching the error. Are try catch blocks scoped in such a way that I cannot throw an error in a nested function, and then expect it to be caught by a catch statement scoped higher up the chain? Some of the sensitive data with in the application that i’m working in has been removed, but it expected that leadInfo[ 0 / 1] would be a 32 character alpha numeric string that I pull from URL parameters.

The underlying issue here is with my AJAX call returning an error from the API and that error not being handled properly within the application. Hence the need for the throw statement. The AJAX call completes fine, and returns a JSON object that does not contain the email address as a property, so I need to handle that in a way that changes the page to reflect that.

    jQuery(document).ready(function(){
        try {
            url = "http://api.com/api/v1/lead/" + leadInfo[1]

            jQuery.ajax({
                type: 'GET',
                contentType: 'application/json',
                url: url,
                dataType : 'jsonp',
                success: function (result) {

                    result = jQuery.parseJSON(result);

                    if(!result.data.email){
                        throw ('New exception');
                    }
                    console.log(result);
                    jQuery('.email').html(result.data.email);
                }
            });


            jQuery('.surveryButton').click(function(){
                window.location.replace("http://" + pgInventory.host + pgInventory.path + leadInfo[0] + "&curLeadId=" + leadInfo[1] + "&curViewedPages=0");
            });
        }
        catch(err) {
            jQuery('.email').html('your e-mail address');
            jQuery('#arrowContent').remove();
        }
});

flavian's user avatar

flavian

28.1k11 gold badges65 silver badges105 bronze badges

asked May 1, 2013 at 10:55

Xenology's user avatar

1

The reason why your try catch block is failing is because an ajax request is asynchronous. The try catch block will execute before the Ajax call and send the request itself, but the error is thrown when the result is returned, AT A LATER POINT IN TIME.

When the try catch block is executed, there is no error. When the error is thrown, there is no try catch. If you need try catch for ajax requests, always put ajax try catch blocks inside the success callback, NEVER outside of it.

Here’s how you should do it:

success: function (result) {
    try {
      result = jQuery.parseJSON(result);

      if (!result.data.email) {
         throw ('New exception');
      }
      console.log(result);
      jQuery('.email').html(result.data.email);
    } catch (exception) {
      console.error("bla");
    };
}

answered May 1, 2013 at 10:58

flavian's user avatar

flavianflavian

28.1k11 gold badges65 silver badges105 bronze badges

3

Due to the asynchronous nature of the callback methods in javascript, the context of the function throwing the error is different compared to the original one. You should do this way:

success: function (result) {
  try {
    result = jQuery.parseJSON(result);
    if(!result.data.email){
      throw ('New exception');
    }
    console.log(result);
    jQuery('.email').html(result.data.email);
  }
  catch(err) {
    // Dealing with the error
  }
}

I would suggest you to have a look at this excellent article about the (very particular) contexts, closures and bindings in Javascript.

CertainPerformance's user avatar

answered May 1, 2013 at 11:02

jap1968's user avatar

jap1968jap1968

7,7271 gold badge30 silver badges37 bronze badges

0

The problem is that ajax is asynchronous by definition. Your exception does not get thrown from within the $.ajax function, but from the callback function on success (which is triggered at a later time).

You should give an error: function(data) {} parameter to it as well, to handle server response errors, and furthermore you should place the try/catch block inside the callback function.

If you really want to catch it outside the callback, then you should consider calling a function rather than throwing an exception, because I don’t see how it can be done.

BenMorel's user avatar

BenMorel

34k49 gold badges179 silver badges318 bronze badges

answered May 1, 2013 at 10:59

MarioDS's user avatar

MarioDSMarioDS

12.9k15 gold badges65 silver badges121 bronze badges

var api_friends_helper = require('./helper.js');
try{
    api_friends_helper.do_stuff(function(result){
        console.log('success');
    };
}catch(err){
    console.log('caught error'); //this doesn't hit!
}

And inside do_stuff, I have:

function do_stuff(){
    //If I put the throw here, it will catch it! 
    insert_data('abc',function(){
        throw new Error('haha');
    });
}

How come it never logs ‘caught error’? Instead, it prints the stack-trace and the error object to screen:

{ stack: [Getter/Setter],
  arguments: undefined,
  type: undefined,
  message: 'haha' }
Error: haha
    at /home/abc/kj/src/api/friends/helper.js:18:23
    at /home/abc/kj/src/api/friends/db.js:44:13
    at Query.<anonymous> (/home/abc/kj/src/node_modules/mysql/lib/client.js:108:11)
    at Query.emit (events.js:61:17)
    at Query._handlePacket (/home/abc/kj/src/node_modules/mysql/lib/query.js:51:14)
    at Client._handlePacket (/home/abc/kj/src/node_modules/mysql/lib/client.js:312:14)
    at Parser.<anonymous> (native)
    at Parser.emit (events.js:64:17)
    at /home/abc/kj/src/node_modules/mysql/lib/parser.js:71:14
    at Parser.write (/home/abc/kj/src/node_modules/mysql/lib/parser.js:576:7)

Notice that if I put the throw RIGHT AFTER the do_stuff(), then it will catch it.

How can I make it catch, even if I put it nested inside another function?

Опубликовано: среда, 29 марта 2023 г. в 09:06

  • JavaScript

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

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

Некоторых ошибок веб-приложений можно избежать, например:

  • Хороший редактор или линтер может отлавливать синтаксические ошибки.
  • Хорошая валидация может выявить ошибки пользовательского ввода.
  • Надёжные процессы тестирования могут обнаруживать логические ошибки.

И всё же ошибки остаются. Браузеры могут сбоить или не поддерживать API, который мы используем. Серверы могут дать сбой или слишком долго отвечать. Сетевое соединение может выйти из строя или стать ненадёжным. Проблемы могут быть временными, но мы не может программировать такие проблемы. Однако мы можем предвидеть проблемы, принимать меры по их устранению и повышать отказоустойчивость нашего приложения.

Отображение сообщения об ошибке — крайняя мера

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

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

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

Как JavaScript обрабатывает ошибки

Когда оператор JavaScript приводит к ошибке, говорят, что он генерирует (выбрасывает) исключение. JavaScript создаёт и выбрасывает объект Error, описывающий ошибку. Мы можем увидеть это в действии на CodePen. Если установить в десятичные разряды (decimal places) отрицательное число, мы увидим сообщение об ошибке в консоли внизу. (Обратите внимание, что мы не встраиваем CodePen в это руководство, потому что нужно иметь возможно видеть вывод консоли, чтобы этот пример имел смысл)

Результат не обновиться, и мы увидим сообщение RangeError в консоли. Следующая функция выдаёт ошибку, когда dp имеет отрицательно значение:

// division calculation
function divide(v1, v2, dp) {

return (v1 / v2).toFixed(dp);

}

После выдачи ошибки интерпретатор JavaScript проверяет наличие кода обработки исключений. В функции Division() ничего нет, поэтому она проверяет вызывающую функцию:

// show result of division
function showResult() {

result.value = divide(
parseFloat(num1.value),
parseFloat(num2.value),
parseFloat(dp.value)
);

}

Интерпретатор повторяет процесс для каждой функции в стеке вызовов, пока не произойдёт одно из следующих событий:

  • Он находит обработчик исключений.
  • Он достигает верхнего уровня кода (что приводит к завершению программы и отображению ошибки в консоли, как показано в примере на CodePen выше).

Перехват исключений

Мы можем добавить обработчик исключений в функцию divide() с помощью блока try...catch:

// division calculation
function divide(v1, v2, dp) {
try {
return (v1 / v2).toFixed(dp);
}
catch(e) {
console.log(`
error name :
${ e.name }
error message:
${ e.message }
`
);
return 'ERROR';
}
}

Функция выполняет код в блоке try {}, но при возникновении исключения выполняется блок catch {} и получает выброшенный объект ошибки. Как и прежде, попробуйте в decimal places установить отрицательное число в этой демонстрации CodePen.

Теперь result показывает ERROR. Консоль показывает имя ошибки и сообщение, но это выводится оператором console.log и не завершает работу программы.

Примечание: эта демонстрация блока try...catch излишняя для базовой функции, такой как divide(). Как мы увидим ниже, проще убедиться, что dp равен нулю или больше.

Можно определить не обязательный блок finally {}, если требуется, чтобы код запускался при выполнении кода try или catch:

function divide(v1, v2, dp) {
try {
return (v1 / v2).toFixed(dp);
}
catch(e) {
return 'ERROR';
}
finally {
console.log('done');
}
}

В консоль выведется done, независимо от того, успешно ли выполнено вычисление или возникла ошибка. Блок finally обычно выполняет действия, которые в противном случае нам пришлось бы повторять как в блоке try, так и в блоке catch. Например, отмену вызова API или закрытие соединения с базой данных.

Для блока try требуется либо блок catch, либо блок finally, либо и то и другое. Обратите внимание, что когда блок finally содержит оператор return, это значение становится возвращаемым значением для всей функции; другие операторы в блоках try или catch игнорируются.

Вложенные обработчики исключений

Что произойдёт, если мы добавим обработчик исключений к вызывающей функции showResult()?

// show result of division
function showResult() {

try {
result.value = divide(
parseFloat(num1.value),
parseFloat(num2.value),
parseFloat(dp.value)
);
}
catch(e) {
result.value = 'FAIL!';
}

}

Ответ… ничего! Блок catch никогда не выполняется, потому что в функции divide() блок catch обрабатывает ошибку.

Тем не менее мы могли бы программно генерировать новый объект Error в divide() и при желании передать исходную ошибку в свойстве cause второго аргумента:

function divide(v1, v2, dp) {
try {
return (v1 / v2).toFixed(dp);
}
catch(e) {
throw new Error('ERROR', { cause: e });
}
}

Это вызовет блок catch в вызывающей функции:

// show result of division
function showResult() {

try {
//...
}
catch(e) {
console.log( e.message ); // ERROR
console.log( e.cause.name ); // RangeError
result.value = 'FAIL!';
}
}

Стандартные типы ошибок JavaScript

Когда возникает исключение, JavaScript создаёт и выдаёт объект, описывающий ошибку, используя один из следующих типов.

SyntaxError

Ошибка, возникающая из-за синтаксически недопустимого кода, такого как отсутствующая скобка:

if condition) { // SyntaxError
console.log('condition is true');
}

Примечание: такие языки, как C++ и Java, сообщают об ошибках синтаксиса во время компиляции. JavaScript — интерпретируемый язык, поэтому синтаксические ошибки не выявляются до тех пор, пока код не запустится. Любой хороший редактор кода или линтер могут обнаружить синтаксические ошибки до того, как мы попытаемся запустить код.

ReferenceError

Ошибка при доступе к несуществующей переменной:

function inc() {
value++; // ReferenceError
}

Опять, хороший редактор кода или линтер могут обнаружить эту проблему.

TypeError

Ошибка возникает, когда значение не соответствует ожидаемому типу, например, при вызове несуществующего метода объекта:

const obj = {};
obj.missingMethod(); // TypeError

RangeError

Ошибка возникает, когда значение не входит в набор или диапазон допустимых значений. Используемый выше метод toFixed() генерирует эту ошибку, потому что он ожидает значение от 0 до 100:

const n = 123.456;
console.log( n.toFixed(-1) ); // RangeError

URIError

Ошибка выдаваемая функциями обработки URI, такими как encodeURI() и decodeURI(), при обнаружении неправильных URI:

const u = decodeURIComponent('%'); // URIError

EvalError

Ошибка возникающая при передаче строки, содержащей не валидный JavaScript код, в функцию eval():

eval('console.logg x;'); // EvalError

Примечание: пожалуйста, не используйте eval()! Выполнение произвольного кода, содержащегося в строке, возможно, созданной на основе пользовательского ввода, слишком опасно!

AggregateError

Ошибка возникает, когда несколько ошибок объединены в одну ошибку. Обычно возникает при вызове такой операции, как Promise.all(), которая возвращает результаты нескольких промисов.

InternalError

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

Error

Наконец, есть общий объект Error, чаще всего используемый при реализации собственных исключений… о котором мы поговорим дальше.

Генерация/выбрасывание собственных исключений

Мы можем использовать throw для генерации/выбрасывания собственных исключений, когда возникает ошибка — или должна произойти. Например:

  • нашей функции не передаются валидные параметры
  • ajax-запрос не возвращает ожидаемые данные
  • обновление DOM завершается ошибкой, поскольку узел не существует

Оператор throw фактически принимает любое значение или объект. Например:

throw 'A simple error string';
throw 42;
throw true;
throw { message: 'An error', name: 'MyError' };

Исключения генерируются для каждой функции в стеке вызовов до тех пор, пока они не будут перехвачены обработчиком исключений (catch). Однако на практике мы хотим создать и сгенерировать объект Error, чтобы он действовал идентично стандартным ошибкам, выдаваемым JavaScript.

Можно создать общий объект Error, передав необязательное сообщение конструктору:

throw new Error('An error has occurred');

Так же Error можно использовать как функцию, без new. Она возвращает объект Error, идентичный приведённому выше:

throw Error('An error has occurred');

При желании можно передать имя файла и номер строки в качестве второго и третьего параметров:

throw new Error('An error has occurred', 'script.js', 99);

В этом редко возникает необходимость, так как по умолчанию они относятся к файлу и строке, где мы вызвали объект Error. (Также их сложно поддерживать, поскольку наши файлы меняются!)

Мы можем определить общие объекты Error, но по возможности следует использовать стандартный тип Error. Например:

throw new RangeError('Decimal places must be 0 or greater');

Все объекты Error имеют следующие свойства, которые можно проверить в блоке catch:

  • .name: имя типа ошибки, например Error или RangeError.
  • .message: сообщение об ошибке.

В Firefox поддерживаются следующие нестандартные свойства:

  • .fileName: файл, в котором произошла ошибка.
  • .lineNumber: номер строки, в которой произошла ошибка.
  • .columnNumber: номер столбца, в котором произошла ошибка.
  • .stack: трассировка стека со списком вызовов функций, сделанных до возникновения ошибки.

Мы можем изменить функцию divide() так, чтобы она вызывала ошибку RangeError, когда количество знаков после запятой не является числом, меньше нуля и больше восьми:

// division calculation
function divide(v1, v2, dp) {

if (isNaN(dp) || dp < 0 || dp > 8) {
throw new RangeError('Decimal places must be between 0 and 8');
}

return (v1 / v2).toFixed(dp);
}

Точно так же мы могли бы выдать Error или TypeError, когда значения делимого не является числом, чтобы предотвратить результат NaN:

  if (isNaN(v1)) {
throw new TypeError('Dividend must be a number');
}

Также можно обрабатывать делитель, который не является числом или равен нулю. JavaScript возвращает Infinity при делении на ноль, но это может запутать пользователя. Вместо того чтобы вызывать общую ошибку, мы могли бы создать собственный тип ошибки DivByZeroError:

// new DivByZeroError Error type
class DivByZeroError extends Error {
constructor(message) {
super(message);
this.name = 'DivByZeroError';
}
}

Затем вызывать/выбрасывать его подобным образом:

if (isNaN(v2) || !v2) {
throw new DivByZeroError('Divisor must be a non-zero number');
}

Теперь добавьте блок try...catch к вызывающей функции showResult(). Он сможет получить тип любой ошибки и отреагировать соответствующим образом — в данном случае, выводя сообщение об ошибке:

// show result of division
function showResult() {

try {
result.value = divide(
parseFloat(num1.value),
parseFloat(num2.value),
parseFloat(dp.value)
);
errmsg.textContent = '';
}
catch (e) {
result.value = 'ERROR';
errmsg.textContent = e.message;
console.log( e.name );
}

}

Попробуйте ввести недопустимые нечисловые, нулевые и отрицательные значения в демонстрации на CodePen.

Окончательная версия функции divide() проверяет все входящие значения и при необходимости выдаёт соответствующую ошибку:

// division calculation
function divide(v1, v2, dp) {

if (isNaN(v1)) {
throw new TypeError('Dividend must be a number');
}

if (isNaN(v2) || !v2) {
throw new DivByZeroError('Divisor must be a non-zero number');
}

if (isNaN(dp) || dp < 0 || dp > 8) {
throw new RangeError('Decimal places must be between 0 and 8');
}

return (v1 / v2).toFixed(dp);
}

Больше нет необходимости размещать блок try...catch вокруг финального return, так как он никогда не должен генерировать ошибку. Если бы это произошло, JavaScript сгенерировал бы свою собственную ошибку и обработал бы её блоком catch в showResult()/

Ошибки асинхронной функции

Мы не можем перехватывать исключения, генерируемые асинхронными функциями на основе обратного вызова, потому что после завершения выполнения блока try...catch выдаётся ошибка. Этот код выглядит правильно, но блок catch никогда не выполнится, и через секунду консоль отобразит сообщение Uncaught Error:

function asyncError(delay = 1000) {

setTimeout(() => {
throw new Error('I am never caught!');
}, delay);

}

try {
asyncError();
}
catch(e) {
console.error('This will never run');
}

Соглашение, принятое в большинстве фреймворков и серверных сред выполнения, таких как Node.js, заключается в том, чтобы возвращать ошибку в качестве первого параметра функции обратного вызова. Это не приведёт к возникновению исключения, хотя при необходимости мы можем вручную сгенерировать ошибку:

function asyncError(delay = 1000, callback) {

setTimeout(() => {
callback('This is an error message');
}, delay);

}

asyncError(1000, e => {

if (e) {
throw new Error(`error: ${ e }`);
}

});

Ошибки на основе промисов

Обратные вызовы могут стать громоздкими, поэтому при написании асинхронного кода предпочтительнее использовать промисы. При возникновении ошибки метод reject() промиса может вернуть новый объект Error или любое другое значение:

function wait(delay = 1000) {

return new Promise((resolve, reject) => {

if (isNaN(delay) || delay < 0) {
reject( new TypeError('Invalid delay') );
}
else {
setTimeout(() => {
resolve(`waited ${ delay } ms`);
}, delay);
}

})

}

Примечание: функции должны быть либо 100% синхронными, либо 100% асинхронными. Вот почему необходимо проверять значение delay внутри возвращаемого промиса. Если бы мы проверили значение delay и выдали ошибку перед возвратом промиса, функция стала бы синхронной при возникновении ошибки.

Метод Promise.catch() выполняется при передаче недопустимого параметра delay и получает возвращённый объект Error:

// invalid delay value passed
wait('INVALID')
.then( res => console.log( res ))
.catch( e => console.error( e.message ) )
.finally( () => console.log('complete') );

Я считаю цепочки промисов немного сложными для чтения. К счастью, мы можем использовать await для вызова любой функции, возвращающей промис. Это должно происходить внутри асинхронной функции, но мы можем перехватывать ошибки с помощью стандартного блока try...catch.

Следующая (вызываемая немедленно) асинхронная функция функционально идентична цепочке промисов выше:

(async () => {

try {
console.log( await wait('INVALID') );
}
catch (e) {
console.error( e.message );
}
finally {
console.log('complete');
}

})();

Исключительная обработка исключения

Выбрасывать объекты Error и обрабатывать исключения в JavaScript легко:

try {
throw new Error('I am an error!');
}
catch (e) {
console.log(`error ${ e.message }`)
}

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

Дополнительная информация:

  • MDN Порядок выполнения и обработка ошибок
  • MDN try…catch
  • MDN Error

В этой статье мы познакомимся с инструкцией для обработки ошибок try...catch и throw для генерирования исключений.

Непойманные ошибки

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

Когда возникает ошибка, выполнение кода прекращается, и эта ошибка выводится в консоль:

const json = '{name:"Александр"}';
const person = JSON.parse(json); // Uncaught SyntaxError: Unexpected token n in JSON at position 1
console.log('Это сообщение мы не увидим!');

Непойманная ошибка в JavaScript

Выполнение этого примера остановится при парсинге строки JSON. В консоль будет выведена непойманная ошибка (uncaught error). Она так называется, потому что мы её не поймали (не обработали). Дальше код выполняться не будет и сообщение, которые мы выводим с помощью console.log() не отобразится.

try…catch

Обработка ошибок в JavaScript осуществляется с помощью try...catch.

try...catch – это специальный синтаксис, состоящий из 2 блоков кода:

try {
  // блок кода, в котором имеется вероятность возникновения ошибки
} catch(error) {
  // этот блок выполняется только в случае возникновения ошибки в блоке try
}

Первый блок идёт сразу после ключевого слова try. В этот блок мы помещаем часть кода, в котором есть вероятность возникновения ошибки.

Второй блок располагается за ключевым словом catch. В него помещаем код, который будет выполнен только в том случае, если в первом блоке возникнет ошибка. В круглых скобках после catch указываем параметр error. В этот параметр будет помещена ошибка, которая возникла в блоке try.

Код, приведённый выше мы обернули в try...catch, а именно ту его часть, в котором может возникнуть ошибка:

const text = '{name:"Александр"}';
try {
  const person = JSON.parse(text); // Uncaught SyntaxError: Unexpected token n in JSON at position 1
} catch(error) {
  console.error(error);
  console.log(error.message);
}
console.log('Это сообщение мы увидим!');

Обработка ошибок в JavaScript

Здесь в блоке try произойдет ошибка, так как в данном примере мы специально присвоили переменной text некорректную строку JSON. В catch эта ошибка будет присвоена параметру error, и в нём мы будем просто выводить эту ошибку в консоль с помощью console.error(). Таким образом она будет выведена также красным цветом, но без слова Uncaught, т.к. эта ошибка была поймана.

Ошибка – это объект и у него имеются следующие свойства:

  • message – описание ошибки;
  • name – тип ошибки, например, RangeError при указании значения выходящего за пределы диапазона;
  • stack – строка стека, которая используется в целях отладки; она позволяет узнать о том, что происходило в скрипте на момент возникновения ошибки.

В этом примере мы также написали инструкцию для вывода описание ошибки error.message в консоль с помощью console.log().

Пример функции для проверки корректности JSON:

const isValidJSON = (text) => {
  try {
    JSON.parse(text);
    return true;
  } catch {
    return false;
  }
}

Функция для проверки корректности JSON, написанная с использование инструкции try...catch

При вызове функции, сначала будет выполняться инструкция JSON.parse(text). Если ошибки не возникнет, то возвратится значение true. В противном случае, интерпретатор перейдёт в секцию catch. В итоге будет возвращено false. Кстати здесь catch записан без указания круглых скобок и параметра внутри них. Эта возможность была добавлена в язык, начиная с версии ECMAScript 2019.

Блок «finally»

В JavaScript возможны три формы инструкции try:

  • try...catch
  • try...finally
  • try...catch...finally

Блок finally выполняется всегда, независимо от того возникли ошибки в try или нет. Он выполняется после try, если ошибок не было, и после catch, если ошибки были. Секция finally не имеет параметров.

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

let result = 0;
try {
  result = sum(10, 20);
  console.log('Это сообщение мы не увидим!');
} catch(error) {
  console.log(error.message);
} finally {
  console.log(result);
}

Пример инструкции try с finally в JavaScript

В этом примере произойдет ошибка в секции try, так как sum нигде не определена. После возникновения ошибки интерпретатор перейдём в catch. Здесь с помощью метода console.log() сообщение об ошибке будет выведено в консоль. Затем выполнится инструкция, находящаяся в блоке finally.

В JavaScript имеется также конструкция без catch:

try {
  // ...
} finally {
  // завершаем какие-то действия
}

Инструкция throw

В JavaScript имеется инструкция throw, которая позволяет генерировать ошибку.

Синтаксис инструкции throw:

throw expression;

Как правило, в качестве выражения обычно используют встроенный основной класс для ошибок Error или более конкретный, например: RangeError, ReferenceError, SyntaxError, TypeError, URIError или другой.

Создаём новый объект Error и выбрасываем его в качестве исключения:

throw new Error('Какое-то описание ошибки');

Пример генерирования синтаксической ошибки:

throw new SyntaxError('Описание ошибки');

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

throw 'Значение не является числом';

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

Например, создадим функцию, которая будет просто выбрасывать новую ошибку:

// создаём стрелочную функцию и присваиваем её переменной myFn
const myFn = () => {
  throw new Error('Описание ошибки');
}
// вызываем функцию
myFn();
console.log('Это сообщение мы не увидим в консоли!');

Генерируем ошибку с помощью throw

Для обработки ошибки обернём вызов функции в try...catch:

const myFn = () => {
  throw new Error('Описание ошибки');
}
try {
  myFn();
} catch(error) {
  console.error(error);
}
console.log('Это сообщение мы увидим в консоли!');

Обрабатываем ошибку в try...catch, сгенерированную с помощью throw

В этом примере вы увидите в консоли ошибку и дальше сообщение, которые мы выводим с помощью console.log(). То есть выполнение кода продолжится.

Кроме встроенных классов ошибок можно создать свои собственные, например, путем расширения Error:

class FormError extends Error {
  constructor(message) {
    super(message);
    this.name = 'FormError';
  }
}

Использование своего класса FormError для отображение ошибок формы:

<form novalidate>
  <input type="text" name="name" required>
  <input type="email" name="email" required>
  <button type="submit">Отправить</button>
</form>

<script>
  class FormError extends Error {
    constructor(message) {
      super(message);
      this.name = 'FormError';
    }
  }
  const elForm = document.querySelector('form');
  elForm.onsubmit = (e) => {
    e.preventDefault();
    elForm.querySelectorAll('input').forEach((el) => {
      if (!el.checkValidity()) {
        try {
          throw new FormError(`[name="${el.name}"] ${el.validationMessage}`);
        } catch(error) {
          console.error(`${error.name} ${error.message}`);
        }
      }
    });
  }
</script>

Создание собственного класса ошибок и использование его для отображение ошибок формы в JavaScript

Глобальная ловля ошибок

Возникновение ошибок, которые мы никак не обрабатываем с помощью try, можно очень просто перехватить посредством window.onerror:

window.onerror = function(message, source, lineno, colno, error) {
  // ...
}

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

  • message — строка, содержащее сообщение об ошибке;
  • source — URL-адрес скрипта или документа, в котором произошла ошибка;
  • lineno и colno — соответственно номер строки и столбца, в которой произошла ошибка;
  • error — объект ошибки или null, если соответствующий объект ошибки недоступен;

Передача ошибок на сервер

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

Пример кода для отправки ошибок, возникающих в браузере на сервер через AJAX с использованием fetch:

window.onerror = (message, source, lineno, colno) => {
  const err = { message, source, lineno, colno };
  fetch('/assets/php/error-log.php', {
    method: 'post',
    body: JSON.stringify(err)
  });
}

На сервере, если, например, сайт на PHP, можно написать такой простенький скрипт:

<?php
define('LOG_FILE', 'logs/' . date('Y-m-d') . '.log');
$json = file_get_contents('php://input');
$data = json_decode($json, true);
try {
  error_log('[' . date('d.m.Y h:i:s') . '] [' . $data['message'] . '] [' . $data['lineno'] . ', ' . $data['colno'] . '] [' . $data['source'] . '] [' . $_SERVER['HTTP_USER_AGENT'] . ']' . PHP_EOL, 3, LOG_FILE);
} catch(Exception $e) {
  $message = implode('; ', $data);
  error_log('[' . date('d.m.Y h:i:s') . '] [' . $message . '] [' . $_SERVER['HTTP_USER_AGENT'] . ']' . PHP_EOL, 3, LOG_FILE);
}

Его следует сохранить в файл /assets/php/error-log.php, а также в этом каталоге создать папку logs для сохранения в ней логов.

В результате когда на клиенте, то есть в браузере будет возникать JavaScript ошибки, они будут сохраняться на сервер в файл следующим образом:

Передача JavaScript ошибок, возникающих в браузере, на сервер

Понравилась статья? Поделить с друзьями:
  • Cat 336 коды ошибок
  • Castlevanialosue exe системная ошибка
  • Casterror код ошибки
  • Cassida zeus ошибка дивертора
  • Cassida coinmax ошибка e1