最近,我在调试一段异步NodeJS代码时遇到了一件非常令人沮丧的事情:一个我认为肯定会在try..catch
中捕获的异常正在泄漏,导致async_foo
函数外出现一个未处理的promise错误。
async function async_foo() {
try {
await some_library.async_bar('some illegal argument');
} catch (err) {
console.error(err); // <- Whether this is called depends on async_bar's implementation !
}
}
从那以后,我了解到在async JS中有几十种方法可以自食其果,因为async。。wait是通过Promises实现的,但仍然是:
是否有可能以绝对肯定总是处理嵌套异步代码错误的方式编写异步JS代码,而不管嵌套异步代码是如何实现的?基于库的解决方案也很重要。
是否有可能以一种绝对肯定总是处理嵌套异步代码错误的方式编写异步JS代码,无论嵌套异步代码是如何实现的?基于库的解决方案也很重要。
不,不是。写得不好的异步代码可能会抛出一个普通的异步回调,该回调由事件循环从空堆栈帧调用,而您无法用try/catch
捕获任何内容。这里有一个微不足道的例子:
setTimeout(() => {
throw new Error("thrown from a setTimeout callback");
}, 10);
除了全局使用类似的东西之外,没有办法从回调本身之外捕获该异常
process.on('uncaughtException', function(err) {
// log and shut down
});
但在这一点上,你没有关于真正发生了什么或如何修复内部状态的上下文。可能有打开的文件或套接字,可能有适当的事件处理程序。可以分配其他资源。内部状态可能会以糟糕的方式遗留下来。此时通常的建议是关闭服务器并重新启动。
事实上,你永远都不想来到这里。你希望错误被知道如何正确清理和处理错误的代码捕获到上下文中,坦率地说,这真的没有任何替代品。
幸运的是,使用promise以及.then()
和.catch()
或await
和try/catch
正确编写的代码会将被拒绝的promise传播回调用链,直到您希望它到达的地方。但是,要做到这一点,代码必须正确编写。即使在使用promise的情况下,写得不好、不连锁或不返回promise的代码仍然会造成异常或拒绝处理不当的情况。
是否有可能以一种绝对肯定总是处理嵌套异步代码错误的方式编写异步JS代码,无论嵌套异步代码是如何实现的?
不,而且可能永远不会。Node.js文档很好地解释了这一点:
根据throw在JavaScript中工作的本质,几乎从来没有任何方法可以安全地"从它停止的地方开始";,而不会泄漏引用,或者创建其他某种未定义的脆性状态。响应抛出的错误最安全的方法是关闭进程。
由库负责解释每种类型的错误,并在发生错误时安全地处理它们并将它们传播(如果必要(给使用者。
您可以使用不推荐使用的CCD_ 8模块,但在这种情况下它可能对您没有帮助,因为";对于未处理的Promise拒绝,不发出'error'
事件&";。