【问题标题】:How to catch uncaught exception in Promise如何在 Promise 中捕获未捕获的异常
【发布时间】:2015-03-16 02:33:10
【问题描述】:

有没有办法全局捕获所有异常,包括 Promise 异常。示例:

    window.onerror = function myErrorHandler(errorMsg, url, lineNumber) {
        alert("Error occured: " + errorMsg);//or any message
        return false;
    }

    var myClass = function(){

    }


    var pr = new Promise(function(resolve, react){
        var myInstance = new myClass();
        myInstance.undefinedFunction(); // this will throw Exception
        resolve(myInstance);
    });


    pr.then(function(result){
        console.log(result);
    });

    // i know right will be this:
    // pr.then(function(result){
    //     console.log(result);
    // }).catch(function(e){
    //     console.log(e);
    // });

这个脚本会默默地死掉而不会出错。 firebug 中什么都没有。

我的问题是,如果我犯了一个错误而忘记捕捉它,有没有办法在全球范围内捕捉它?

【问题讨论】:

    标签: javascript exception promise


    【解决方案1】:

    更新,原生承诺现在在大多数浏览器中执行以下操作:

    window.addEventListener("unhandledrejection", function(promiseRejectionEvent) { 
        // handle error here, for example log   
    });
    

    前几天我们刚刚讨论过这个问题。

    这是你如何用蓝鸟做到这一点:

    window.onpossiblyunhandledexception = function(){
        window.onerror.apply(this, arguments); // call
    }
    
    window.onerror = function(err){
        console.log(err); // logs all errors
    }
    

    对于 Bluebird,也可以使用 Promise.onPossiblyUnhandledRejection。不需要对 done 的调用,因为与 Q 不同,库本身会检测到未处理的拒绝(2016 年更新 - 我现在为 Q 编写了代码,它会这样做)。

    至于原生承诺 - 它们最终报告给 window.onerror 或新的处理程序,但规范过程尚未完成 - 你可以follow it here

    【讨论】:

    • > 在大多数浏览器中:According to MDN,截至 2018 年 6 月,唯一支持此功能的浏览器是 Chrome。
    • @JohnHatton 根据statcounter 大多数浏览器都是Chrome。也就是说 - 你总是可以使用一个承诺库来获得这种行为。我在 Firefox(有标志)Safari 和 Edge 中对人们进行了 ping 操作,看看我们是否可以很快在更多浏览器中做到这一点。
    • “大多数浏览器都是 Chrome” 好吧,我想“大多数会话中使用的浏览器”是“大多数浏览器”的一种定义......不是我会选择的那种。
    • 看起来像最新版本的蓝鸟,你需要做的基本上就是window.addEventListener("unhandledrejection", function(event) {})bluebirdjs.com/docs/api/…——我可能误读了文档,但听起来蓝鸟现在会触发unhandledrejection 为您举办的活动
    • @DevinRhode 是的,我们现在就这样做
    【解决方案2】:

    大多数 Promise 实现目前不提供您所指的功能类型,但是许多 3rd-party Promise 库(包括 Qbluebird)提供了一个 done() 方法,该方法将捕获并重新抛出任何未捕获的错误,从而将它们输出到控制台。

    编辑:参见 Benjamin Gruenbaum 关于 Bluebird 处理未捕获异常的功能的回答)

    因此,如果您有这种情况,您只需要遵循经验法则,即您使用的任何承诺都应该被退回或以.done() 终止:

    pr.then(function(result){
        console.log(result);
    })
    .done();
    

    引用 Q API 参考:

    donethen 用法的黄金法则是:return 您对他人的承诺,或者如果链以您结束,请致电 done 终止它。以catch 终止是不够的,因为catch 处理程序本身可能会引发错误。

    我意识到这仍然需要一些额外的工作,您仍然可以忘记这样做,但与必须 .catch() 并明确处理每个错误相比,这是一个改进,尤其是出于上述原因。

    【讨论】:

    • 实际上完成与简单地执行.catch(thrower) 没有任何不同(或使用快捷方式执行相同操作,例如添加Promise.prototype.done = ...。因此,为此目的毫无意义,尤其是在报告未捕获错误的蓝鸟中正常。
    • @Esailija 你能详细说明一下吗?在这种情况下,thrower 会是什么?
    • @Esailija 好的,在 Bluebird 中可能不需要它,但它仍然是防止错误在其他一些实现 (AFAIK) 中完全被吞没的最简单方法,所以我不会说它毫无意义。
    • @JLRishe 我认为他的观点是人们不应该使用能吞下错误的 Promise 实现(如 jQuery、Q、$q 等)并使用允许您跟踪未处理的拒绝(如 Bluebird)的 Promise 库,什么时候,回复等。
    • 除了美化的 catch settimeout throw 之外,我的意思是作为一个单独的概念毫无意义
    【解决方案3】:

    在 Node.js 中,您可以使用:

    process.on('unhandledRejection', (reason, promise) => {
      console.error(`Uncaught error in`, promise);
    });
    

    【讨论】:

    • 这在在未知环境中调试时很有用,但如果您知道哪个承诺并有权访问,您应该使用.catch.done 以获得更好的可维护性
    • 在较新版本的 Node 中,这实际上已成为标准行为。因此,即使不添加这段代码,也会记录未捕获的 Promise 中的错误。
    • 你怎么能得到导致这种情况的承诺?还是函数文件?问题是 reason.stack 总是未定义的。
    • 使用promise(或setTimeout)会创建一个新的栈,所以你看不到promise是从哪里调用的。虽然较新版本的 Chrome (V8?) 允许您查看以前的堆栈,但对调试异步代码有很大帮助。
    【解决方案4】:

    如果您正在编写可以在浏览器和 Node.js 环境中执行的代码,您可以将代码包装在这样的自执行函数中:

    var isNode = (typeof process !== 'undefined' && typeof process.on !== 'undefined');
    (function(on, unhandledRejection) {
        // PUT ANY CODE HERE
        on(unhandledRejection, function(error, promise) {
            console.error(`Uncaught error in`, promise);
        });
        // PUT ANY CODE HERE
    })(
        isNode ? process.on.bind(process) : window.addEventListener.bind(window),
        isNode ? "unhandledRejection" : "unhandledrejection"
    );
    

    如果你使用这段代码会发生什么:

    • 如果您在 Node.js 环境中运行它,您的处理程序将附加到进程对象并在您在 Promise 中有未捕获的异常时执行。

    • 如果您在浏览器环境中运行它,您的处理程序将附加到窗口对象,并在您在 Promise 中有未捕获的异常并且您的浏览器支持 unhandledrejection 事件时执行。

    • 如果您在不支持 unhandledrejection 的浏览器环境中运行它,您将无法捕获未捕获的异常并且您的 unhandledrejection 事件处理程序将永远不会被触发,但您不会如果没有未捕获的异常,则会出现任何错误。

    【讨论】:

      【解决方案5】:

      如果您使用的是原生 Promise,则非常简单。
      你只需要.catch这个reject某处即可。

      ajax(request).catch(function(rejected){
            console.log(rejected);
      });
      

      如果我没有在某个地方捕捉到它,那么未捕捉到的承诺将继续显现。 但是如果我在某个地方抓住它......

      【讨论】:

      • 这不能回答所提出的问题。
      • 即使你抓住了它,通知也会出现在控制台(Firefox)中。
      猜你喜欢
      • 2018-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-28
      • 2023-03-12
      • 1970-01-01
      • 2018-01-14
      相关资源
      最近更新 更多