#javascript #promise #try-catch
Вопрос:
const errorTest = async() => {
const result = await $.get("http://dataa.fixer.io/api/latest?access_key=9790286e305d82fbde77cc1948cf847camp;format=1");
return resu<
}
try {
errorTest()
}
catch(err) {
console.log("OUTSIDE ERROR!" err)
}
URL-адрес намеренно неверен, чтобы выдать ошибку, но внешняя catch()
сторона не фиксирует ее. Почему?
Если я использую then()
и catch()
вместо этого, это работает.
errorTest()
.then(val=> console.log(val))
.catch(err=> console.error("ERROR OCCURRED"))
Это работает, но try {..} catch()
не работает. Почему?
Я продолжаю получать Uncaught (in promise) error
.
Комментарии:
1. Вам нужно
await errorTest()
для того, чтобы получить ошибку вcatch
блоке. В противном случае вам нужно прикрепить.catch()
обработчик.2.
await errorTest()
не работает. Это дает мне ошибку «ожидание допустимо только в асинхронных функциях и телах модулей верхнего уровня».catch()
обработчик работает, но я не понимаю, почему. Мне нужно, чтобы кто-нибудь объяснил мне это более подробно. Я думал, что использованиеasync
возвращает обещание, так почему жеcatch()
снаружи его не ловят?3. @Snirka
then()
не возвращает обещание, оно решает обещание. Остальная часть вашего комментария вообще не касается моего вопроса.4. Послушайте, если вы выполняете функцию, которая возвращает обещание, а вы его не
await
выполняете, это решится позже. И любая обработка также будет позже. Такone(); try { asyncFn() } catch() {} two();
позвонитone
, тогдаasyncFn
потом не жди, а звониtwo
. Что бы ни случилось с обещанием, это произойдет в будущем после того, как этот код завершит выполнение `one(); попробуйте { await asyncFn() } поймать() {} два (); » вместо этого будет ждать разрешения обещания отasyncFn
перед вызовомtwo
. И еслиasyncFn
это приведет к отклонению, оно попадет в блок catch.5.
try
В обработке обещаний нет ничего особенногоcatch
. Этоawait
с отклоненным обещанием, которое вызовет отклонение и, таким образом, вызоветcatch
блокировку.
Ответ №1:
async function errorTest() { /* ... */ }
try {
errorTest()
}
catch(err) {
console.log("OUTSIDE ERROR!" err)
}
Потому errorTest
async
что он всегда будет возвращать обещание и никогда не начнет выполнение именно там , где вы его вызываете: он асинхронен. errorTest
возвращает, и вы выходите из try
блока, прежде errorTest
чем будет запущена одна строка кода внутри. Таким образом, ваш catch
блок никогда не сработает, потому что ничто в errorTest
нем не будет синхронно вызывать исключение.
Отклонение обещания и исключения-это два разных канала отказа: отклонение обещания является асинхронным, а исключения являются синхронными. async
любезно преобразует синхронные исключения ( throw
) в асинхронные исключения (отклонение обещания), но в остальном это две совершенно разные системы.
function errorTest() {
return new Promise(/* ... */); // nothing throws!
}
function errorTestSynchronous() {
throw new Error(/* ... */); // always throws synchronously
}
function errorTestMixed() {
// throws synchronously 50% of the time, rejects 50% of the time,
// and annoys developers 100% of the time
if (Math.random() < 0.5) throw new Error();
return new Promise((resolve, reject) => { reject(); });
}
Здесь вы можете увидеть различные формы метания. Первый errorTest
, в точности эквивалентен вашему: async
функция работает так , как будто вы переработали свой код в новое обещание. Второе, errorTestSynchronous
, выполняется синхронно: это вызовет ваш catch
блок, но из-за того, что он синхронный, вы потеряли возможность реагировать на другие асинхронные действия, такие как ваш $.get
вызов. Наконец, errorTestMixed
может потерпеть неудачу в обоих направлениях: Он может бросить, а может и отвергнуть обещание. Поскольку все синхронные ошибки могут быть асинхронными, и весь асинхронный код должен иметь .catch()
в любом случае, в цепочке обещаний для ошибок редко требуются оба типа ошибок в одной и той же функции.
Как и в ответе Айотунде Аджайи, вы можете решить эту проблему, используя await
для преобразования вашей асинхронной ошибки в синхронную, поскольку await
она превратит сбой обещания обратно в вызванное исключение:
// within an async function
try {
await errorTest()
}
catch(err) {
console.log("OUTSIDE ERROR!" err)
}
Но за кулисами все будет выглядеть именно так, как вы предложили в своем вопросе:
errorTest()
.then(val=> console.log(val))
.catch(err=> console.error("ERROR OCCURRED"))
Комментарии:
1. Итак, проблема в том, что,
try{}
не фиксирует обещание и , следовательно, не передает ошибку обещанияcatch()
, или в том, что, поскольку онаtry{}
не синхронизирована, JS выполняет ее, но не ждет возвращаемого значения, вместо этого выполняетсяcatch()
сразу, что приводит кcatch()
тому, что ошибка, вызванная ею, не принимаетсяtry{}
? Я попробовал тот же пример, но с примитивным значением,const result = a - c; return result
,c
было не определено, и это сработало,catch()
поймал ошибку. Итак, является ли первое объяснение правильным?2. Кроме того, извините, но я не совсем понял ваши примеры. В вашем первом примере вы возвращаете новое обещание, так что … если внутри есть ошибка, как ничего не будет выброшено? Во втором примере вы просто определяете новую ошибку.. какое это имеет отношение к вопросу? Вы много подчеркиваете синхронный и асинхронный аспект кода, но я как бы создал мысленный образ захвата обещания против не захвата, разрешения против не разрешения … и акцент на асинхронности против синхронизации на самом деле не так сильно резонирует со мной. Я надеюсь, что в этом есть смысл.
3. Вся моя цель состояла в том, чтобы иметь два
catch()
, чтобы продемонстрировать, что если есть ошибка, тоcatch()
ближайшая функция, которая вызвала ошибку, зафиксирует ее, но я изо всех сил пытаюсь придумать подобный случай.4.Это отличный ответ от Джеффа. @happy_story Для того, чтобы вы
try
catch
работали, как указано выше, вам нужно добавитьawait
ключевое слово перед вызовом функции, так как за кулисами цепляется.catch()
за результат, если произошел сбой.
Ответ №2:
Вам нужно дождаться errorTest
const callFunction=async()=>{
try{
const result = await errorTest()
}catch(err){
console.log(err)
}
}
callFunction ()
Обратите внимание, что функция await errorTest() также должна быть в асинхронной функции. Вот почему я поместил его в функцию вызова ()
Другой Вариант
const errorTest = async() => {
try{
const result = await $.get("http://dataa.fixer.io/api/latest?access_key=9790286e305d82fbde77cc1948cf847camp;format=1");
console.log(result)
}catch(err){
console.log(err)
}
}
Комментарии:
1. Пример, который вы мне приводите, сильно отличается от моего примера. Я не хочу помещать «попробуй и поймай» в функцию. Если вы собираетесь ответить на мой вопрос, сделайте это так, как я его задал. Не меняйте вопрос.
2. Из вашего кода следует, что вы не ожидаете «erroTest()» в блоке try catch,поэтому у вас «ошибка, не обнаруженная (в обещании)». И блок try catch должен быть в асинхронной функции, потому что вам нужно дождаться «errorTest()», чтобы он работал.
3. Итак, вы хотите сказать, что
catch()
это не фиксирует ошибку, потому что само обещание не было зафиксировано, потомуtry {}
что не фиксирует обещание, в то.then()
время как делает? Но есть ли какой-то тип ошибки? В этом случае ошибка была вызвана неработающей ссылкой, так похоже ли это на ошибку обещания, и чтобы зафиксировать ее, обещание должно быть зафиксировано в первую очередь? Что, если я совершу ошибку другого рода, сработает ли это тогда? И есть ли способ зафиксировать обещание вне функции в моем примере?4. Да.Поскольку
errorTest
он асинхронен, он вернет обещание и будет выполняться только тогда, когда вы будете ожидать его асинхронной функции. Вот почему ты это сделал"Uncaught (in promise) error"
. Если выerrorTest()
консолируете функцию в блоке try catch вашего примера, она у вас будет"<pending>"
, что означает, что вы ее не ждете. Если вы намеренно допустите ошибку, это сработает. Вы можете зафиксировать обещание внеerrorTest()
функции, поместив блок try catch в другую асинхронную функцию и вызвав функцию, как в моем примере. Если это ошибка, она попадет в блок catch5. Вы вызвали
errorTest()
функцию внутри второгоtry/catch
блока, хотя и в console.log. Таким образом , ошибка поймана, потому что вы бросили ошибку в первомcatch()
, поэтому, когда вы это сделали и вызвали функцию во второмtry/catch
блоке , она вошла во второйcatch
, но если бы вы не бросили ошибку в первом илиconsole.log
в первомcatch
, она не была бы поймана во второмcatch