Почему try {} .. catch() не работает с функцией async/await?

#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 в другую асинхронную функцию и вызвав функцию, как в моем примере. Если это ошибка, она попадет в блок catch

5. Вы вызвали errorTest() функцию внутри второго try/catch блока, хотя и в console.log. Таким образом , ошибка поймана, потому что вы бросили ошибку в первом catch() , поэтому, когда вы это сделали и вызвали функцию во втором try/catch блоке , она вошла во второй catch , но если бы вы не бросили ошибку в первом или console.log в первом catch , она не была бы поймана во втором catch