为啥 try .. catch() 不能与 async/await 函数一起使用?

Posted

技术标签:

【中文标题】为啥 try .. catch() 不能与 async/await 函数一起使用?【英文标题】:Why is try .. catch() not working with async/await function?为什么 try .. catch() 不能与 async/await 函数一起使用? 【发布时间】:2022-01-21 21:30:19 【问题描述】:

const errorTest = async() =>  

  const result = await $.get("http://dataa.fixer.io/api/latest?access_key=9790286e305d82fbde77cc1948cf847c&format=1");

  return result;




 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

【问题讨论】:

您需要await errorTest() 才能在catch 块中获得错误。否则你需要附加一个.catch() 处理程序。 await errorTest() 不起作用。它给了我`等待仅在异步函数和模块的顶层主体中有效`错误。 catch() 处理程序有效,但我不明白为什么。我需要有人更详细地向我解释这一点。我以为使用async 会返回一个承诺,那么为什么外面的catch() 没有捕捉到它呢? @Snirka then() 不返回承诺,而是解决承诺。您的其余评论根本没有解决我的问题。 看,如果你执行一个返回promise的函数而你没有await,那么稍后会解决。任何处理也将在以后进行。所以one(); try asyncFn() catch() two(); 会调用one,然后asyncFn 然后 等待,然后调用two。在这段代码执行完 one(); 之后,无论 promise 发生什么,都将在未来发生。 try await asyncFn() catch() two();` 将在调用 two 之前等待来自 asyncFn 的承诺解决。如果asyncFn 导致拒绝,它将进入 catch 块。 try/catch 在处理承诺方面没有什么特别之处。带有被拒绝承诺的 await 将引发拒绝,从而触发 catch 块。 【参考方案1】:

你需要等待errorTest

const callFunction=async()=>
try
const result = await errorTest()
catch(err)
console.log(err)


callFunction ()

请注意,await errorTest() 函数也必须在异步函数中。这就是为什么我把它放在 callFunction() 里面

另一种选择

const errorTest = async() =>  
try
const result = await $.get("http://dataa.fixer.io/api/latest?access_key=9790286e305d82fbde77cc1948cf847c&format=1");

  console.log(result)
catch(err)
console.log(err)



【讨论】:

你给我的例子和我的例子很不一样。我不想把 try and catch 放在函数里面。如果您要回答我的问题,请按照我提出的方式进行。不要改变问题。 从您的代码中,您没有在 try catch 块中等待“erroTest()”,这就是您遇到“未捕获(承诺中)错误”的原因。并且 try catch 块必须在异步函数中,因为您必须等待“errorTest()”才能使其工作。 所以,你的意思是说,catch() 没有捕获错误,因为没有捕获承诺本身,因为try 没有捕获承诺,而.then() 捕获?但是有没有一种错误?在这种情况下,错误是由断开的链接引起的,那么这是否像一个promise错误,要捕获它,必须先捕获promise?如果我犯了另一种错误怎么办,那它会起作用吗?在我的示例中,有没有办法在函数之外捕获承诺? 是的。因为errorTest 是异步的,所以它会返回一个promise,并且只会在你等待它一个异步函数时执行。这就是为什么你有"Uncaught (in promise) error"。如果您在示例的 try catch 块中控制台 errorTest() 函数,您将拥有 "<pending>",这意味着您不会等待它。如果你故意犯错误,它会起作用。您可以通过将 try catch 块放在另一个异步函数中并调用该函数来捕获 errorTest() 函数之外的承诺,如我的示例所示。如果是错误,就会进入catch块 您在第二个 try/catch 块中调用了 errorTest() 函数,尽管是在 console.log 中。所以错误被捕获是因为你在第一个catch()中抛出了错误,所以,当你这样做时,你在第二个try/catch块中调用了函数,它进入了第二个catch,但如果你没有' t 在第一个中抛出错误,或者 console.log 在第一个 catch 中抛出错误,它不会在第二个中被捕获 catch【参考方案2】:
async function errorTest()  /* ... */ 

try  
  errorTest()

catch(err)  
  console.log("OUTSIDE ERROR!" + err)

因为errorTestasync,它会总是返回一个promise,并且永远不会在你调用它的地方开始执行:它是异步。 errorTest 返回,然后您退出 try 块,然后运行 ​​errorTest 中的一行代码。因此,您的 catch 块将永远不会触发,因为 errorTest 中的任何内容都不会同步抛出异常。

Promise 拒绝和异常是两种不同的失败渠道:Promise 拒绝是异步的,而异常是同步的。 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 函数的工作方式就像您已将代码重构为新的 Promise。第二个,errorTestSynchronous,同步抛出:它会触发你的catch 块,但是因为它是同步的,你已经失去了对其他异步操作做出反应的机会,比如你的$.get 调用。最后,errorTestMixed 可能会以两种方式失败:它可以抛出,也可以拒绝承诺。由于所有同步错误都可以异步处理,并且所有异步代码都应该有.catch() promise 链接以检测错误,因此在同一个函数中很少需要两种类型的错误。


在 Ayotunde Ajayi 的回答中,您可以通过使用 await 将异步错误转换为同步显示来解决此问题,因为 await 会将 Promise 失败解包回抛出的异常:

// 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"))

【讨论】:

所以,问题是try 没有捕获承诺,因此没有将承诺错误传递给catch(),或者因为try 是未同步,JS 执行它但不等待返回值,而是立即执行catch(),导致catch() 没有收到try 抛出的错误?我尝试了相同的示例,但使用原始值 const result = a - c; return resultc 未定义,并且它有效,catch() 捕获了错误。那么,第一个解释正确吗? 另外,很抱歉,我不太理解你的例子。在您的第一个示例中,您正在返回一个新的承诺,所以.. 如果里面有错误,怎么会不会抛出任何东西?在您的第二个示例中,您只是定义了一个新的错误。这与问题有什么关系?您非常强调代码的同步与异步方面,但我已经建立了一个捕获承诺与不捕获,解决与不解决的心理形象......并且对异步与同步的强调并没有真正引起共鸣我很喜欢。我希望这是有道理的。 我的整个目的是有两个catch(),以证明如果出现错误,最接近产生错误的函数的catch() 将捕获它,但我很难提出有这样的情况。

以上是关于为啥 try .. catch() 不能与 async/await 函数一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

为啥尽量不要将try…catch写在循环中?

为啥在 Try ... Catch 中使用 finally

为啥 try..catch..finally 块的 finally 节在 catch 之前运行?

为啥 Try/Catch 块会创建新的变量范围?

求教大神,java中的jdbc程序为啥要加finally,不是加了try catch以后,后面的语句就会执行了啊

用powershell的try catch, 为啥try里面出现异常,catch 捕获不到呢?