#javascript #node.js #error-handling #async-await
#javascript #node.js #обработка ошибок #async-await
Вопрос:
Когда исключение поймано, остальная часть кода все еще выполняется.
function bad(){
//throw new Error('I am an exception')
return Promise.reject("I am an exception")
}
(
async function (){
let msg = await bad().catch( e=>console.log("This is an error: " e))
console.log("I want to stop before executing this line ")
}
)()
Я пытаюсь поймать исключение таким образом, вместо того, чтобы пытаться поймать
Моя первая проблема заключается в том, как остановить доступ кода к остальной части кода после обнаружения ошибки.
Вторая проблема заключается в том, что если я заменю отклонение обещания на закомментированную ошибку throw, выданное исключение не будет перехвачено, почему это?
Ответ №1:
Потому что вы преобразуете отклонение в выполнение с помощью вашего catch
обработчика. await
Будет ожидать обещания, возвращенного catch
, которое никогда не отклоняется. Таким образом, нет причин, по которым код не продолжался бы, поскольку await
видит только выполненное (никогда не отклоненное) обещание.
Помните, что catch
возвращает новое обещание, которое будет выполнено на основе того, что делает обработчик отклонения. Ваш обработчик отклонения подавляет ошибку, эффективно возвращая undefined
, таким образом выполняя обещание.
Это очень похоже на то, как если бы вы сделали это:
async function (){
let msg;
try {
msg = await bad();
} catch (e) {
console.log("This is an error: " e);
}
console.log("I want to stop before executing this line ")
}
В комментарии, который вы спросили:
Итак, нет другого способа, кроме как включить весь мой код в блок try и использовать только однострочный
.catch()
, если у меня больше нет кода для выполнения?
Просто чтобы убрать это с пути: обычно лучше всего вообще не обрабатывать ошибки ни в какой функции, кроме точки входа верхнего уровня в код (например, функции, вызываемые на верхнем уровне вашего кода или обработчиками событий). Обработка ошибок слишком рано — это классический антипаттерн. Разрешить им распространяться на вызывающую программу, где они могут обрабатываться централизованным образом.
Но в ситуациях, когда уместно обрабатывать ошибку на этом уровне, да, try
/ catch
, вероятно, ваш лучший выбор со следующей логикой в try
блоке:
async function() {
try {
let msg = await bad();
console.log("I want to stop before executing this line ")
} catch (e) {
console.log("This is an error: " e);
}
}
Его преимущество также заключается в том, что в содержащей области видимости не объявлена переменная, которую вы не собираетесь использовать. Если для вас важна «однострочная» функция, то между .catch
и catch
вообще нет большой разницы:
async function() {
try {
let msg = await bad();
console.log("I want to stop before executing this line ")
} catch (e) { console.log("This is an error: " e); }
}
Или вы могли бы вернуть какое-либо значение флага:
async function() {
let msg = await bad().catch(e => { console.log("This is an error: " e); return null; });
if (msg === null) {
return;
}
console.log("I want to stop before executing this line ")
}
Но, честно говоря, это действительно плывет против течения. 🙂
Комментарии:
1. @YoussefMohamed — Я обновил ответ, чтобы учесть ваш первый комментарий. Боюсь, я не понимаю, о чем вы спрашиваете во втором.
2. @YoussefMohamed — Ты имеешь в виду
function bad(){ throw new Error('I am an exception'); }
? Посколькуbad
это неasync
функция, то это синхронная ошибка, вызванная вызовомbad
, которая заставляетasync
функцию, из которой вы ее вызываете, отклонять свое обещание. Оно не переходит кcatch
потому чтоbad()
завершается ошибкой. (Даже если бы это было не так, оно не вернуло бы обещание.) Если быbad
это былаasync
функция, онаthrow
действительно была бы перехвачена.catch
обработчиком.3. (Просто примечание: я подробно рассматриваю promises в главе 8 моей новой книги и
async
/await
в главе 9. Ссылки в моем профиле, если вам интересно.)4. @YoussefMohamed — Верно, это та же ситуация, что и выше —
bad()
часть генерирует синхронное исключение, поэтому она не возвращает обещание, поэтому нет обещания вызвать.catch
метод, так что … 🙂5. Просто чтобы немного добавить: Полезно помнить, что
.then
/.catch
не является специальным синтаксисом, это просто вызовы метода для объекта, возвращаемого функцией, которая возвращает обещание. Напротив, внутриasync
функции поведениеtry
/catch
,throw
и даже циклов (если в цикле естьawait
) изменены для поддержки асинхронного выполнения.