为啥 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)
因为errorTest
是async
,它会总是返回一个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 result
,c
未定义,并且它有效,catch()
捕获了错误。那么,第一个解释正确吗?
另外,很抱歉,我不太理解你的例子。在您的第一个示例中,您正在返回一个新的承诺,所以.. 如果里面有错误,怎么会不会抛出任何东西?在您的第二个示例中,您只是定义了一个新的错误。这与问题有什么关系?您非常强调代码的同步与异步方面,但我已经建立了一个捕获承诺与不捕获,解决与不解决的心理形象......并且对异步与同步的强调并没有真正引起共鸣我很喜欢。我希望这是有道理的。
我的整个目的是有两个catch()
,以证明如果出现错误,最接近产生错误的函数的catch()
将捕获它,但我很难提出有这样的情况。以上是关于为啥 try .. catch() 不能与 async/await 函数一起使用?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 try..catch..finally 块的 finally 节在 catch 之前运行?