Javascript Bluebird(或其他Promise库)保留Promise错误堆栈跟踪

Javascript Bluebird(或其他Promise库)保留Promise错误堆栈跟踪,javascript,stack,promise,try-catch,bluebird,Javascript,Stack,Promise,Try Catch,Bluebird,好吧,我可能只是错过了显而易见的,但我似乎找不到这个问题的一般答案,我的谷歌Fu迄今为止让我失望 在承诺的捕获处理程序中,如何在保留原始错误的承诺堆栈跟踪的同时重新抛出错误 这可能不是正确的描述,因此下面是一个示例: 使用此代码,跟踪堆栈为: Warning: a promise was rejected with a non-error: [object String] at RejectWithAnError (https://fiddle.jshell.net/_display/

好吧,我可能只是错过了显而易见的,但我似乎找不到这个问题的一般答案,我的谷歌Fu迄今为止让我失望

在承诺的捕获处理程序中,如何在保留原始错误的承诺堆栈跟踪的同时重新抛出错误

这可能不是正确的描述,因此下面是一个示例:

使用此代码,跟踪堆栈为:

Warning: a promise was rejected with a non-error: [object String]
    at RejectWithAnError (https://fiddle.jshell.net/_display/:51:19)
    at https://fiddle.jshell.net/_display/:57:14
From previous event:
    at StartTheProgram (https://fiddle.jshell.net/_display/:56:6)
    at window.onload (https://fiddle.jshell.net/_display/:67:1)
bluebird.js:1444 Unhandled rejection an error occurred
但是,如果添加了catch处理程序,并且错误被重新拒绝或从该处理程序中重新抛出,则堆栈将成为新拒绝方法调用的位置:

跟踪此堆栈跟踪的:

Warning: a promise was rejected with a non-error: [object String]
    at https://fiddle.jshell.net/_display/:65:23
From previous event:
    at StartTheProgram (https://fiddle.jshell.net/_display/:61:11)
    at window.onload (https://fiddle.jshell.net/_display/:70:1)
bluebird.js:1444 Unhandled rejection an error occurred
您可以看到调度原始错误“RejectWithAnError”的内部方法在捕获并重新抛出错误时从第二个堆栈中消失

以下是来自JSFIDLE的完整代码(最新的Bluebird作为外部依赖项引用):

(顺便说一句,这是我的第一个堆栈溢出问题,所以我希望这是这个问题的正确格式。)


编辑:更新示例以拒绝使用从新的
错误
实例继承的对象实例。

JavaScript中的错误会在创建时捕获其跟踪,因此每当您重试错误时,它将自动捕获堆栈跟踪

但是,您没有抛出错误。出于这个原因,蓝鸟给了你一个警告(耶,我们)。如果您坚持抛出非错误而不是正确地子类化错误,那么您需要通过手动捕获对象来手动欺骗对象,使其具有正确的堆栈跟踪。通过在构造函数内创建
新错误
,并将
.stack
设置为其堆栈(可能需要进行一些解析),或者通过调用特定方法:

function RejectWithAnError() {
    var err = {error: true, message: "an error occurred"};
    // err.__proto__ = new Error(); -- this is how you'd do it with prototypes btw
    // explicitly capture the stack trace of the object
    if(Error.captureStackTrace) Error.captureStackTrace(err);
}

小提琴。请注意,
.prototype
是函数用来指示通过将函数作为构造函数调用而创建的对象原型的属性。为了直接设置对象的原型,您可以调用
\uuuuu proto\uuuu
,尽管这很少是一个特别好的主意。下面是一个带有。

侧注的示例:始终使用
错误
构造函数的实例拒绝。
状态
是一个字符串,不能保存堆栈信息。这就是为什么您应该始终使用
Error
对象的原因。谢谢您的指针。我已经更新了JSFIDLE以使用一个错误实例:原始堆栈跟踪肯定很有用,理想情况下,它将通过复杂的承诺链保留导致错误的承诺链。例如,在Bluebird中启用长堆栈跟踪时,您可以看到导致失败的所有承诺,但是如果我添加一个catch处理程序,它似乎会在承诺链中调用该catch处理程序之前丢失任何信息。感谢您的响应。我认为从你的意见中我得到的一个重要信息是,我从错误的角度看待这个问题。如果我想看到Bluebird打印的完整调试堆栈跟踪,返回到启动当前拒绝链的第一个拒绝的原始位置,这可能是有问题的;(实际上,这看起来几乎像Bluebird必须提供的东西,相当于
Error.captureStackTrace(err);
,但对于异步调用堆栈,例如一个名为
Bluebird.captureStackTrace(err);
的方法)(从上一条评论继续,似乎一条评论中包含的字符太多了。)但是,如果提供给拒绝调用的对象始终是
错误的实例
,那么在承诺链中该点之后的任何
捕获
处理程序中都可以知道发送错误的原始文件位置,并且一旦知道该位置,那么如果未捕获的异常跟踪可能并不重要由Bluebird打印完成。再次感谢您的输入,这肯定很有帮助。+1,但您能否演示
对象的使用。setPrototypeOf
而不是弃用的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu@Bergi@BenjaminGruenbaum:这两个都是-被
setPrototypeOf
,一个D标准化(向后)兼容性(检查附件B介绍)。我认为它过时了——它不应该出现在新的代码中。
function RejectWithAnError() {
    var err = {error: true, message: "an error occurred"};
    // err.__proto__ = new Error(); -- this is how you'd do it with prototypes btw
    // explicitly capture the stack trace of the object
    if(Error.captureStackTrace) Error.captureStackTrace(err);
}
Promise.config({
    warnings: false
});