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?
-
Вопрос заданболее двух лет назад
-
941 просмотр
Вы какую ошибку пытаетесь отловить?
При 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)
}
}
-
Показать ещё
Загружается…
29 янв. 2023, в 03:07
300000 руб./за проект
29 янв. 2023, в 02:16
700000 руб./за проект
29 янв. 2023, в 01:54
5000 руб./за проект
Минуточку внимания
Есть две разных вещи, которые называются одним и тем же словом. «Исключения Си++» — это программные исключения, которые вызывает оператор throw. Такие исключения являются частью алгоритма работы программы, с точки зрения операционной системы и процессора это всего лишь исполняемый код, который трактуется как ошибка (да и то не всегда и не везде) лишь на уровне сознания человека. «Аппаратные исключения» — это то, что вызывает аппаратура при неправильной работе программы. Т.е. программа пытается что-то выполнить, чего выполнять нельзя в принципе (типа деления на ноль или обращение по несуществующему адресу)
![]()
Сообщение от hiphone

нарушение прав доступа при чтении по адресу 0xABABABB3
Адрес 0xABABABB3 очень похож на искусственно созданный кривой адрес для облегчения контроля по некорректным адресам. Т.е. в реальности произошло аппаратное исключение, которое оператором catch НЕ ловится.
Аппаратные исключения ловятся через обработчики сигналов (см. документацию по signal, sigaction). В виндовых компиляторах есть какие-то расширения __try и __catch, которые вроде бы и используются для обработки аппаратных исключений и скорее всего являются обёртками над обработчиками сигналов. Но это уже мои личные предположения, я с этим делом никогда не работал, просто временами мельком видел в чужих кодах
Я работаю над проектом, используя АНТЛР библиотека парсеров для C #. Я построил грамматику для анализа текста, и она хорошо работает. Однако, когда синтаксический анализатор обнаруживает недопустимый или неожиданный токен, он выдает одно из многих исключений. Проблема в том, что в некоторых случаях (не во всех) мой блок try / catch не может его поймать и вместо этого останавливает выполнение как необработанное исключение.
Проблема для меня в том, что я не могу воспроизвести эту проблему где-либо еще, кроме как в моем полном коде. Стек вызовов показывает, что исключение определенно возникает в моем блоке try / catch (Exception). Единственное, о чем я могу думать, это то, что между моим кодом и кодом, генерирующим исключение, происходит несколько вызовов сборки ANTLR, и в этой библиотеке не включена отладка, поэтому я не могу пройти через нее. Интересно, запрещают ли не отлаживаемые сборки пузыри исключений? Стек вызовов выглядит так: вызовы внешней сборки находятся в Antlr.Runtime:
Expl.Itinerary.dll! TimeDefLexer.mTokens () Строка 1213 C # Antlr3.Runtime.dll! Antlr.Runtime.Lexer.NextToken () + 0xfc байтов Antlr3.Runtime.dll! Antlr.Runtime.CommonTokenStream.FillBuffer () + 0x22c bytes Antlr3.Runtime.dll! Antlr.Runtime.CommonTokenStream.LT (int k = 1) + 0x68 байт Expl.Itinerary.dll! TimeDefParser.prog () Строка 109 + 0x17 байт C # Expl.Itinerary.dll! Expl.Itinerary.TDLParser .Parse (string Text = "", Expl.Itinerary.IItinerary Itinerary = {Expl.Itinerary.MemoryItinerary}) Строка 17 + 0xa байтов C #
Фрагмент кода из самого нижнего вызова в Parse () выглядит так:
try {
// Execution stopped at parser.prog()
TimeDefParser.prog_return prog_ret = parser.prog();
return prog_ret == null ? null : prog_ret.value;
}
catch (Exception ex) {
throw new ParserException(ex.Message, ex);
}
На мой взгляд, предложение catch (Exception) должно было фиксировать любое исключение. Есть ли причина, по которой это не так?
Обновление: Я проследил внешнюю сборку с помощью Reflector и не обнаружил никаких доказательств наличия резьбы. Сборка кажется просто служебным классом времени выполнения для кода, сгенерированного ANTLR. Исключение создается методом TimeDefLexer.mTokens (), его тип — NoViableAltException, который является производным от RecognitionException -> Exception. Это исключение возникает, когда лексер не может понять следующий токен в потоке; другими словами, неверный ввод. Это исключение должно произойти, но оно должно было быть обнаружено моим блоком try / catch.
Кроме того, повторное генерирование ParserException действительно не имеет отношения к этой ситуации. Это уровень абстракции, который принимает любое исключение во время синтаксического анализа и преобразует его в мое собственное исключение ParserException. Проблема с обработкой исключений, с которой я столкнулся, никогда не достигает этой строки кода. Фактически, я закомментировал часть «выбросить новое исключение ParserException» и все равно получил тот же результат.
Еще одна вещь: я изменил исходный рассматриваемый блок try / catch, чтобы вместо этого перехватить NoViableAltException, исключив любую путаницу наследования. Я все равно получил тот же результат.
Кто-то однажды предположил, что иногда VS слишком активен при перехвате обработанных исключений в режиме отладки, но эта проблема также возникает в режиме выпуска.
Чувак, я все еще в тупике! Я не упоминал об этом раньше, но я использую VS 2008, и весь мой код — 3.5. Внешняя сборка — 2.0. Кроме того, некоторые из моих кодов являются подклассами класса сборки 2.0. Может ли несовпадение версий вызвать эту проблему?
Обновление 2: Мне удалось устранить конфликт версий .NET, перенеся соответствующие части моего кода .NET 3.5 в проект .NET 2.0 и воспроизведя тот же сценарий. Мне удалось воспроизвести одно и то же необработанное исключение при последовательной работе в .NET 2.0.
Я узнал, что ANTLR недавно выпустил 3.1. Итак, я обновился с 3.0.1 и повторил попытку. Оказывается, сгенерированный код немного переработан, но в моих тестовых примерах возникает то же необработанное исключение.
Обновление 3:
Я воспроизвел этот сценарий в упрощенный проект VS 2008. Не стесняйтесь скачивать и проверять проект на себе. Я применил все замечательные предложения, но пока не смог преодолеть это препятствие.
Если вы можете найти обходной путь, поделитесь своими выводами. Спасибо еще раз!
Спасибо, но VS 2008 автоматически прерывается при необработанных исключениях. Кроме того, у меня нет диалогового окна «Отладка-> Исключения». Вызываемое исключение NoViableAltException полностью предназначено и предназначено для перехвата пользовательским кодом. Поскольку он не перехватывается должным образом, выполнение программы неожиданно останавливается как необработанное исключение.
Выброшенное исключение является производным от Exception, и многопоточность с ANTLR не выполняется.
Конструкция try...catch пытается выполнить инструкции в блоке try, и, в случае ошибки, выполняет блок catch.
Синтаксис
try {
try_statements
}
[catch (exception_var_1 if condition_1) { // не стандартно
catch_statements_1
}]
...
[catch (exception_var_2) {
catch_statements_2
}]
[finally {
finally_statements
}]
try_statements-
Инструкции для выполнения.
catch_statements_1,catch_statements_2-
Инструкции, которые будут выполнены, если произойдёт ошибка в блоке
try.
exception_var_1,exception_var_2-
Идентификатор для хранения объекта ошибки, который впоследствии используется в блоке
catch
condition_1-
Условное выражение.
finally_statements-
Инструкции, которые выполняются после завершения блока
try. Выполнение происходит в независимости от того, произошла ошибка или нет.
Описание
Конструкция try содержит блок try, в котором находится одна или несколько инструкций (Блок ({} ) обязательно должен присутствовать, даже если выполняется всего одна инструкция), и хотя бы один блок catch или finally. Таким образом, есть три основные формы конструкции try:
try {...} catch {...}try {...} finally {...}try {...} catch {...} finally {...}
Блок catch содержит инструкции, которые будут выполнены, если в блоке try произошла ошибка. Если любая инструкция в блоке try выбрасывает исключение, то управление сразу же переходит в блок catch. Если в блок try не было выброшено исключение, то блок catch не выполняется.
Блок finally выполнится после выполнения блоков try и catch, но перед инструкциями, следующими за конструкцией try...catch. Он выполняется всегда, в независимости от того, было исключение или нет.
Вы можете использовать вложенные конструкции try. Если внутренняя конструкция try не имеет блока catch (такое может быть при её использовании в виде try {...} finaly {...}, потому что try {...} не может быть без блоков catch или finally), будет вызван сatch внешней конструкции try.
Конструкция try также используется для обработки исключений JavaScript (то есть, выброшенных внутренними функциями языка или парсером). Загляните в JavaScript руководство для дополнительной информации о JavaScript исключениях.
Безусловный блок catch
При использовании блока catch, он вызывается для любого исключения в блоке try. Например, когда в следующем коде происходит ошибка, управление переходит к блоку catch.
try {
throw 'myException'; // создание исключения
}
catch (e) {
// инструкции для обработки ошибок
logMyErrors(e); // передать объект исключения обработчику ошибок
}
Блок catch задаёт идентификатор (e в примере выше) который содержит объект исключения (в примере выше — значение, переданное оператору throw). Область видимости этого объекта ограничивается блоком catch.
Условный блок catch
«Условные блоки catch» можно создавать, используя try...catch с if...else if...else, как здесь:
try {
myroutine(); // может выбрасывать три вида исключений
} catch (e) {
if (e instanceof TypeError) {
// обработка исключения TypeError
} else if (e instanceof RangeError) {
// обработка исключения RangeError
} else if (e instanceof EvalError) {
// обработка исключения EvalError
} else {
// обработка остальных исключений
logMyErrors(e); // передать обработчику ошибок
}
}
Частый сценарий использования — обработать известные исключения, а при неизвестных ошибках, пробросить их дальше:
try {
myRoutine();
} catch(e) {
if (e instanceof RangeError) {
// обработка известного исключения, с которым
// понятно, что делать
} else {
throw e; // пробросить неизвестные ошибки
}
}
Примечание: Обратите внимание: Firefox раньше поддерживал краткую запись условных блоков catch:
try {
myroutine(); // может выбрасывать три вида исключения
} catch (e if e instanceof TypeError) {
// обработка исключений TypeError
} catch (e if e instanceof RangeError) {
// обработка исключений RangeError
} catch (e if e instanceof EvalError) {
// обработка исключений EvalError
} catch (e) {
// обработка остальных исключения
logMyErrors(e);
}
Однако, такой синтаксис никогда не был частью спецификации ECMAScript и был удалён из Firefox после версии 59. Сейчас он не поддерживается ни в одном браузере.
Идентификатор исключения
Когда в блоке try выбрасывается исключение, exception_var (т. е. e в конструкции catch (e)) содержит значение исключения. Его можно использовать, чтобы получить больше информации об выброшенном исключении. Идентификатор доступен только в области видимости блока catch.
try {
if (!firstValidation()) {
throw 1;
}
if (!secondValidation()) {
throw 2;
}
} catch (e) {
// Выводит 1 или 2 (если не произошло никаких других ошибок)
console.log(e);
}
Блок finally
Блок finally содержит код который будет запущен после кода в блоках try и catch. Обратите внимание, что код в блоке finally запускается в независимости от того, было ли выброшено исключение или нет. Также код в блоке finally будет запущен вне зависимости от того, присутствует блок catch или нет. Блок finally можно использовать для того, чтобы скрипт безопасно завершил работу в случае ошибки. Например, если необходимо освободить память и ресурсы которые использовал скрипт.
Наличие специального блока, связанного с ошибкой, который выполняется вне зависимости от наличия исключительной ситуации, может показаться странным, но эта конструкция на самом деле весьма полезна. Рассмотрим пример кода:
function expensiveCalculations() {
// Сложные вычисления
}
function maybeThrowError() {
// Функция, которая может выбросить исключение
if(Math.random() > 0.5) throw new Error()
}
try {
// Теперь при прокрутке страницы будут происходить
// сложные вычисления, что сильно скажется на
// производительности
window.addEventListener('scroll', expensiveCalculations)
maybeThrowError()
} catch {
// Если функция maybeThrowError выбросит исключения,
// управление сразу перейдёт в блок catch и
// сложные вычисления продолжат выполняться до
// перезагрузки страницы
maybeThrowError()
}
window.removeEventListener('scroll', expensiveCalculations)
В этом примере, если функция maybeThrowError выбросит исключение внутри блока try, управление перейдёт в блок catch. Если и в блоке catch эта функция тоже выбросит исключение, то выполнение кода прервётся, и обработчик события не будет снят, пока пользователь не перезагрузит страницу, что плохо скажется на скорости работы. Для того, чтобы избежать таких ситуаций, следует использовать блок finally:
try {
window.addEventListener('scroll', expensiveCalculations)
maybeThrowError()
} catch {
maybeThrowError()
} finally {
window.removeEventListener('scroll', expensiveCalculations)
}
Другой пример: работа с файлами. В следующем фрагменте кода показывается, как скрипт открывает файл и записывает в него какие-то данные (в серверном окружении JavaScript имеет доступ к файловой системе). Во время записи может произойти ошибка. Но после открытия файл очень важно закрыть, потому что незакрытый файл может привести к утечкам памяти. В таких случаях используется блок finally:
openMyFile();
try {
// Сделать что-то с файлом
writeMyFile(theData);
}
finally {
closeMyFile(); // Закрыть файл, что бы ни произошло
}
Примеры
Вложенные блоки try
Для начала давайте посмотрим что делает этот код:
try {
try {
throw new Error('упс');
}
finally {
console.log('finally');
}
}
catch (e) {
console.error('внешний блок catch', e.message);
}
// Вывод:
// "finally"
// "внешний блок catch" "упс"
Теперь отловим исключение во внутреннем блоке try, добавив к нему блок catch:
try {
try {
throw new Error('упс');
}
catch (e) {
console.error('внутренний блок catch', e.message);
}
finally {
console.log('finally');
}
}
catch (e) {
console.error('внешний блок catch', e.message);
}
// Output:
// "внутренний блок catch" "упс"
// "finally"
Наконец, пробросим ошибку
try {
try {
throw new Error('упс');
}
catch (e) {
console.error('внутренний блок catch', e.message);
throw e;
}
finally {
console.log('finally');
}
}
catch (e) {
console.error('внешний блок catch', e.message);
}
// Вывод:
// "внутренний блок catch" "oops"
// "finally"
// "внешний блок catch" "oops"
Любое исключение будет передано только в ближайший блок catch, если он не пробросит его дальше. Все исключения, выброшенными внутренними блоками (потому что код в блоке catch также может выбросить исключение), будут пойманы внешними.
Возвращение значения из блока finally
Если блок finally возвращает какое-либо значение, оно становится значением, которое возвращает вся конструкция try...catch...finally, вне зависимости от любых инструкций return в блоках try и catch. Также игнорируются исключения, выброшенные блоком catch.
try {
try {
throw new Error('упс');
}
catch (e) {
console.error('внутренний блок catch', e.message);
throw e;
}
finally {
console.log('finally');
return;
}
}
catch (e) {
console.error('внешний блок catch', e.message);
}
// Output:
// "внутренний блок catch" "упс"
// "finally"
«упс» не доходит до внешнего блока из-за инструкции return в блоке finally. То же самое произойдёт с любым значением, возвращаемым из блока catch.
Спецификации
| Specification |
|---|
| ECMAScript Language Specification # sec-try-statement |
Совместимость
BCD tables only load in the browser
Смотрите также
В этой статье мы познакомимся с инструкцией для обработки ошибок try...catch и throw для генерирования исключений.
Непойманные ошибки
Ошибке в коде могут возникать по разным причинам. Например, вы отправили запрос на сервер, а он дал сбой и прислал ответ, который привёл к неожиданным последствиям. Кроме этой, могут быть тысячи других, а также свои собственные.
Когда возникает ошибка, выполнение кода прекращается, и эта ошибка выводится в консоль:
const json = '{name:"Александр"}';
const person = JSON.parse(json); // Uncaught SyntaxError: Unexpected token n in JSON at position 1
console.log('Это сообщение мы не увидим!');

Выполнение этого примера остановится при парсинге строки JSON. В консоль будет выведена непойманная ошибка (uncaught error). Она так называется, потому что мы её не поймали (не обработали). Дальше код выполняться не будет и сообщение, которые мы выводим с помощью console.log() не отобразится.
Обработка ошибок в 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('Это сообщение мы увидим!');

Здесь в блоке 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.parse(text). Если ошибки не возникнет, то возвратится значение true. В противном случае, интерпретатор перейдёт в секцию catch. В итоге будет возвращено false. Кстати здесь catch записан без указания круглых скобок и параметра внутри них. Эта возможность была добавлена в язык, начиная с версии ECMAScript 2019.
Блок «finally»
В JavaScript возможны три формы инструкции try:
try...catchtry...finallytry...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, так как 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('Это сообщение мы не увидим в консоли!');

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

В этом примере вы увидите в консоли ошибку и дальше сообщение, которые мы выводим с помощью 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>

Глобальная ловля ошибок
Возникновение ошибок, которые мы никак не обрабатываем с помощью 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 ошибки, они будут сохраняться на сервер в файл следующим образом: