编辑:总的来说,这个问题是关于node.js中的unhandledRejection
的。我没有期待一个没有被期待的承诺(但后来失败了)来使程序崩溃-因为我没有意识到unhandledRejection
被抛出并导致node.js退出。刷新我对unhandledRejection
的理解,我现在意识到**程序中任何地方的任何承诺都会被拒绝而没有catch()语句将抛出unhandledRejection并在默认情况下退出node.js进程。**这对我来说没有太大意义,但至少我理解了为什么会发生这种情况。
在下面的代码示例中,thisFailsLater最初成功返回,但稍后会引发错误。
这会导致runTest()传递try/catch并继续下一个等待。
但是,在等待下一个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)
这是我没想到的:看起来一个异步函数最初可以成功返回,但是任何被调用但没有在返回后抛出的函数内等待的异步函数将使Node.JS进程崩溃。
我对这个工作原理的理解正确吗?如果正确,当thisFailsLater()在成功返回后抛出2秒时,我如何阻止Node.JS退出?这完全打破了我对Promises工作原理的理解(只能解决或出错一次)。
错误再现:
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)
})
2条答案
按热度按时间taor4pac1#
看起来异步函数最初可以成功返回,但是在返回后抛出的函数中调用但未等待的任何异步函数都将导致Node.JS进程崩溃。
我说的对吗?
是的,但这并不是
async
函数所独有的--在node.js中任何函数都可以做到这一点:如果是这样,当
thisFailsLater()
在成功返回2秒后抛出时,如何防止Node.JS退出?别那么做。
不要让函数异步引发异常。
要防止nodejs退出,可以使用hook on the global
error
andunhandledrejection
events,但这些都是用于日志记录的-您的应用程序已经遇到了不可恢复的错误。这完全打破了我对承诺如何工作的理解(只能解决或出错一次)。
它与promise无关,promise * do * 只在
async
函数体结束求值时结算一次,thisFails()
是第二个单独的promise -独立于执行流,因为你没有await
它。x8diyxa72#
问题发生在以下位置:
当你不对承诺执行
await
操作时,你就无法处理拒绝,await
关键字所做的事情之一就是将一个被拒绝的承诺“转换”为异步上下文中的异常--来自await
的MDN文档:如果承诺被拒绝,则
await
表达式将引发被拒绝的值。包含await
表达式的函数将出现在错误的堆栈跟踪中。否则,如果未等待被拒绝的承诺或立即返回被拒绝的承诺,则调用方函数将不会出现在堆栈跟踪中。因为你没有
await
被拒绝的承诺,它不能在你的try
块中被捕获,转换为异常,并在控制流转换期间作为参数传递给catch
子句。如果你没有await
承诺,但想处理拒绝,你必须使用.catch()
方法承诺语法: