在 unhandledrejection 事件处理程序中获取堆栈跟踪

phi*_*294 9 javascript stack-trace promise

当我只使用处理程序捕获 Promise 拒绝时,如何确定发生在哪里onunhandledrejection

\n

\r\n
\r\n
console.error = ()=>{}\nwindow.addEventListener(\'unhandledrejection\', (promiseRejectionEvent) => {\n  console.log(\'unhandled: \', Error().stack)\n})\n\nfunction main() {\n  new Promise(() => { throw null })\n}\nmain()
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

如果运行此命令后检查浏览器的控制台,您将看到类似以下内容的内容:

\n

来源选项卡\n控制台输出

\n

唯一Error().stack的在其堆栈跟踪中包含拒绝处理程序函数本身(灰色输出js:14:30)。但浏览器似乎确实知道拒绝发生在哪里:还有另一个红色错误输出(Uncaught (in promise) null),指向目标行(js:18)。如何获取该线路信息?

\n

后一个输出似乎是由浏览器的内部完成的,因为它无法通过console.error像上面的示例中那样的覆盖来防止。正如MDNpromiseRejectionEvent.preventDefault()上所解释的,只能通过调用来防止这种情况。但我无论如何都不想阻止它,而是检索它,例如用于记录目的。

\n

现实世界用例:当然可以不依赖onunhandledrejection事件处理程序,例如通过添加.catch()短语或至少抛出throw new Error(null)。但就我而言,我无法控制它,因为它是第三方代码。今天它在客户端浏览器上意外抛出(可能是库错误),并且自动错误报告不包含堆栈跟踪。我试图缩小上述根本问题的范围。谢谢!

\n
\n

编辑回应评论:

\n
\n

将第三方代码包装在 try/catch 中?\xe2\x80\x93 世界

\n
\n

好点,但这没有帮助,因为拒绝实际上发生在回调内:

\n

\r\n
\r\n
window.addEventListener(\'unhandledrejection\', (promiseRejectionEvent) => {\n  console.log(\'unhandled: \', Error().stack) // <- stack once again does *not* include "main()", it is only printed out in the console\n})\n\nfunction main() {\n  try {\n    thirdPartyModule()\n  } catch(e) {\n    // Never caught\n    console.log("caught:", e)\n  }\n}\n\n// Example code\n// We cannot change this function\nfunction thirdPartyModule() {\n  setTimeout(() =>\n    new Promise(() =>\n      { throw null }))\n}\n\nmain()
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

小智 4

免责声明:使用此解决方法对于调试很有用,但会对性能产生轻微的负面影响,并可能导致各种库行为不当;它不应该在生产代码中使用。


您可以将 Promise 构造函数替换为您自己的实现,其中包含创建它的堆栈跟踪。

window.Promise = class FAKEPROMISE extends Promise {
    constructor() {
        super(...arguments);
        this.__creationPoint = new Error().stack;
    }
};
Run Code Online (Sandbox Code Playgroud)

这将为您提供创建任何给定承诺的点的堆栈跟踪。请注意.then.catch、 和.finally都创建了新的 Promise。

这不适用于async函数创建的 Promises,因为它们不使用窗口的Promise构造函数。

promise这可以通过阅读以下成员来使用PromiseRejectionEvent

window.addEventListener('unhandledrejection', (promiseRejectionEvent) => {
  console.log('unhandled: ', promiseRejectionEvent.promise.__creationPoint)
})
Run Code Online (Sandbox Code Playgroud)

这将打印类似的内容:

unhandled:  Error
    at new FAKEPROMISE (script.js:4:32)
    at main (script.js:6:3)
    at script.js:9:1
Run Code Online (Sandbox Code Playgroud)