首页 文章

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

提问于
浏览
1

好吧,我可能只是错过了显而易见的事情,但我似乎无法找到对此的一般答案,而我的谷歌到目前为止还没有让我失望 .

在Promise的Catch处理程序中,如何重新抛出错误,同时仍保留原始错误的Promise堆栈跟踪?

这可能不是正确的描述,所以这是一个例子:

https://jsfiddle.net/8sgj8x4L/19/

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

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处理程序,并且从该处理程序重新拒绝或重新抛出错误,则堆栈将成为新的Reject方法调用的位置:

https://jsfiddle.net/8sgj8x4L/18/

跟踪此堆栈跟踪:

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”从第二个堆栈中消失,因为错误被捕获并重新抛出 .

作为参考,这里是JSFiddle的完整代码(最新的Bluebird被引用为外部依赖):

window.P.longStackTraces();

function RejectWithAnError() {
        var err = {error: true, message: "an error occurred"};
        err.prototype = new Error();
        return window.P.reject(err);
}

function StartTheProgram() {
    return RejectWithAnError()

    // Comment out this catch handler completely, and the Promise stack trace will correctly show the "RejectWithAnError" method as the error origin.
    .catch(function (status) {
            console.log("[WARN] Catch handler was called.");
            // Neither of these lines will show "RejectWithAnError" in the Promise chain stack trace.
            // throw status;
            return window.P.reject(status);

    });
}

StartTheProgram()

(另一方面,这是我的第一个Stack Overflow问题,所以我希望这是这个问题的正确格式 . )

Edit: 更新了拒绝使用从新 Error 实例继承的对象实例的示例 .

2 回答

  • 2

    JavaScript中的错误会在创建时捕获它们的跟踪,因此每当您重新抛出错误时,它都会自动捕获堆栈跟踪 .

    但是你不会抛出错误 . 出于这个原因,蓝鸟正在给你一个警告(我们) . 如果你坚持抛出非错误而不是正确地继承错误 - 你需要通过手动捕获它来手动欺骗对象以获得正确的堆栈跟踪 . 通过在构造函数中创建 new Error 并将 .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);
    }
    

    小提琴here . 只需注意, .prototype 是函数使用的属性,用于指示通过将函数作为构造函数调用而创建的对象的原型 . 为了直接设置对象的原型,你可以调用 __proto__ ,尽管's rarely a particularly good idea. Here'是一个带有proto instead of Error.captureStackTrace的例子 .

  • 0
    Promise.config({
        warnings: false
    });
    

相关问题