简体   繁体   English

Node.JS:带有未等待的异步函数调用的 unhandledRejection

[英]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 the await 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 退出,您可以挂接全局errorunhandledrejection事件,但这些事件用于记录 - 您的应用程序已经遭受无法恢复的错误。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM