[英]Node.JS: unhandledRejection with async function calls that are not awaited
Edit : in summary this issue is regarding unhandledRejection
in node.js.编辑:总而言之,这个问题与 node.js 中的unhandledRejection
有关。 I didn't expect a promise that was not awaited (but later fails) to crash the program - because I didn't realize that unhandledRejection
was being thrown & causing node.js to exit.我没想到没有等待(但后来失败)的承诺会使程序崩溃——因为我没有意识到unhandledRejection
被抛出并导致 node.js 退出。 Refreshing my understanding of unhandledRejection
I now realize that any promise anywhere in the program that is rejected without a catch() statement will throw unhandledRejection and exit the node.js process on default.刷新我对unhandledRejection
的理解我现在意识到程序中任何地方的任何承诺如果在没有 catch() 语句的情况下被拒绝,将抛出 unhandledRejection 并默认退出 node.js 进程。 Which doesn't make too much sense to me, but at least I understand why it's happening.这对我来说意义不大,但至少我明白为什么会这样。
In the following code example, thisFailsLater initially returns successfully, but then throws an error some time later.在下面的代码示例中,thisFailsLater 最初返回成功,但稍后会抛出错误。
This results in runTest() passing the try/catch and moving on to the next await.这导致 runTest() 通过 try/catch 并继续进行下一个等待。
However, while waiting for the next await call, thisFailsLater then throws an error, which causes Node.JS to exit:但是,在等待下一个 await 调用时,thisFailsLater 会抛出错误,导致 Node.JS 退出:
% node t.js
Throwing error in 2 seconds
thisFailsLater returned successfully
t.js:4
throw new Error('thrown error in thisFails()')
^
Error: thrown error in thisFails()
at thisFails (t.js:4:9)
This is something I didn't expect: it seems that an async function can initially return successfully, but then any async function called but not awaited within the function that throws after returning will then crash the Node.JS process.这是我没想到的:似乎一个异步函数最初可以成功返回,但是随后在返回后抛出的函数内调用但未等待的任何异步函数都会导致 Node.JS 进程崩溃。
Am I correct in how this works?我对它的工作原理是否正确? And if so, how can I prevent Node.JS from exiting when thisFailsLater() throws 2 seconds after returning successfully?如果是这样,当 thisFailsLater() 在成功返回后 2 秒抛出时,如何防止 Node.JS 退出? This completely breaks my understanding of how Promises work (can only be resolved or errored once).这完全打破了我对 Promise 工作原理的理解(只能解决或出错一次)。
Error reproduction:错误重现:
async function thisFails() {
console.log('Throwing error in 2 seconds')
await new Promise((resolve) => setTimeout(resolve, 2e3));
throw new Error('thrown error in thisFails()')
}
async function thisFailsLater() {
try {
// NOTE: intentionally NOT awaiting this call here.
thisFails()
} catch (err) {
console.log('thisFailsLater caught error', err)
}
}
async function runTest() {
try {
await thisFailsLater()
} catch (err) {
console.error('runTest caught error', err)
}
console.log('thisFailsLater returned successfully')
await new Promise((resolve) => setTimeout(resolve, 3e3));
}
runTest().then(() => {
process.exit(0)
}).catch((err) => {
// NOTE: the error that Node.JS crashes with is NOT logged here!
console.error('Caught error in main()', err)
process.exit(1)
})
The problem occurs here:问题出现在这里:
async function thisFailsLater() {
try {
// NOTE: intentionally NOT awaiting this call here.
thisFails()
} catch (err) {
console.log('thisFailsLater caught error', err)
}
}
When you don't await
the promise (which rejects), you fail to handle the rejection.当您不await
承诺(拒绝)时,您将无法处理拒绝。 One of the things that the await
keyword does is "convert" a rejected promise into an exception in the async context — from the MDN documentation for await
: await
关键字所做的其中一件事是在异步上下文中将被拒绝的承诺“转换”为异常——来自await
的 MDN 文档:
If the promise is rejected, the
await
expression throws the rejected value.如果 promise 被拒绝,则await
表达式会抛出被拒绝的值。 The function containing theawait
expression will appear in the stack trace of the error.包含await
表达式的函数将出现在错误的堆栈跟踪中。 Otherwise, if the rejected promise is not awaited or is immediately returned, the caller function will not appear in the stack trace.否则,如果拒绝的承诺没有等待或立即返回,调用函数将不会出现在堆栈跟踪中。
Because you don't await
the rejected promise, it can't be caught in your try
block, converted to an exception, and passed as the argument to the catch
clause during the transition of control flow.因为你不await
被拒绝的承诺,它不能在你的try
块中被捕获,转换为异常,并在控制流转换期间作为参数传递给catch
子句。 If you don't await
the promise, but want to handle the rejection, you must use the .catch()
method promise syntax:如果您不await
承诺,但想处理拒绝,则必须使用.catch()
方法承诺语法:
function thisFailsLater() {
return thisFails().catch(exception => console.log('thisFailsLater caught error', exception));
}
It seems that an async function can initially return successfully, but then any async function called but not awaited within the function that throws after returning will then crash the Node.JS process.似乎异步函数最初可以成功返回,但随后在返回后抛出的函数中调用但未等待的任何异步函数都会导致 Node.JS 进程崩溃。
Am I correct in how this works?我对它的工作原理是否正确?
Yes.是的。 But this is not unique to async
functions - any function can do that in node.js:但这并不是async
函数独有的——任何函数都可以在 node.js 中做到这一点:
function failLater() {
setTimeout(() => {
throw new Error("crash!");
}, 1000);
return "success"
}
And if so, how can I prevent Node.JS from exiting when
thisFailsLater()
throws 2 seconds after returning successfully?如果是这样,当thisFailsLater()
在成功返回后 2 秒抛出时,如何防止 Node.JS 退出?
Just don't do that.™只是不要那样做。™
Do not let functions cause exceptions asynchronously.不要让函数异步引发异常。
To prevent nodejs from exiting, you can hook on the global error
and unhandledrejection
events , but those are meant for logging - your application already has suffered from an unrecoverable error.为防止 nodejs 退出,您可以挂接全局error
和unhandledrejection
事件,但这些事件用于记录 - 您的应用程序已经遭受无法恢复的错误。
This completely breaks my understanding of how Promises work (can only be resolved or errored once).这完全打破了我对 Promise 工作原理的理解(只能解决或出错一次)。
It's not related to promises, the promise does settle only once, when the body of the async
function concludes evaluating.它与承诺无关,当async
函数的主体结束评估时,承诺只会结算一次。 The thisFails()
is a second, separate promise - independent from the flow of execution since you didn't await
it. thisFails()
是第二个独立的承诺 - 独立于执行流程,因为您没有await
它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.