如何在 Promise 的回调中捕获未捕获的异常

Posted

技术标签:

【中文标题】如何在 Promise 的回调中捕获未捕获的异常【英文标题】:How to catch an Uncaught exception in a callback in a promise 【发布时间】:2018-01-27 09:40:33 【问题描述】:

我对 node.js 有一个大问题。

关于信息,我使用了 0.12 版本,因为我们的应用程序非常复杂和庞大,无法轻松迁移到最新版本。

而且,许多函数都是回调函数。

但是,在这个项目的新部分中,我想使用 Promises 轻松捕获错误。而且我在事件循环中遇到了未捕获的异常问题。

这是测试代码:

process.on('uncaughtException', function (err) 
    console.error('Uncaught Exception');
);

new Promise(function () 
    process.nextTick(function () 
        var a = null;

        a.b;
    );
).catch(function (e) 
    console.log('catched by Promise');
);

如果我测试这段代码,我会系统地传递给uncaughtException

可以用 Promise 捕获这种类型的错误吗?

谢谢

【问题讨论】:

【参考方案1】:

Promise 将在两个地方自动为您捕获异常:1) 在 Promise 执行器函数中和 2) 在 .then().catch() 处理程序中。在这两种情况下,它们都会捕获异常并将其转换为被拒绝的承诺。以下是几个例子:

// Promise executor
new Promise(function(resolve, reject) 
    var a = null;
    a.b = 0;      // throws an exception
    resolve("done");
).then(function(data) 
    console.log(data);     // never gets here
).catch(function(err) 
    console.log(err);      // shows the above exception
);

// .then() handler
Promise.resolve().then(function(data) 
    var a = null;
    a.b = 0;      // throws an exception
    return "hello";
).then(function(data) 
    console.log(data);     // never gets here
).catch(function(err) 
    console.log(err);      // shows the above exception
);

因此,如果您承诺所有异步操作,以便所有完成或错误处理程序都是 .then() 处理程序或 .catch() 处理程序,那么承诺基础设施将捕获所有这些异常。但是,它不会捕获这些情况之外的异常。如果您正在使用setTimeout() 或任何其他未包含在 Promise 中的异步操作,那么您必须自己将这些回调包装在 try/catch 中。但是,做起来很简单。可以使用基于 Promise 的简单函数来代替 setTimeout()

所以,不要这样:

setTimeout(someFunction, 100);

你可以用这个:

delay(10).then(someFunction).catch(...);

delay()的实现是这样的:

function delay(t) 
    return new Promise(function(resolve) 
        setTimeout(resolve, t);
    );

现在,someFunction() 中的所有同步异常都将为您捕获。如果它执行自己的异步操作,那么也必须将其转换为使用 Promise。

当然,您可以将自己的 try/catch 包装在其他情况下,以在其他地方捕获您自己的异常。


您可以使用 Bluebird 的 Promise.promisifyAll() 之类的东西来制作整个界面的承诺版本。例如,我一直将它与fs 模块一起使用来制作整个fs 接口的promisified 版本,这样我就可以对所有文件访问功能使用promises。您可以在这里查看更多关于使用 Bluebird 的原因:Are there still reasons to use promise libraries like Q or BlueBird now that we have ES6 promises?


在您的具体示例中:

new Promise(function () 
    process.nextTick(function () 
        var a = null;

        a.b;
    );
).catch(function (e) 
    console.log('catched by Promise');
);

您在异步回调中抛出异常,该异常不是承诺为您捕获异常的条件之一。我能想到的主要是这样的:

// wrapper function to run a function upon nextTick and catch exceptions in it
function nextTick(fn) 
    return new Promise(function(resolve, reject) 
        process.nextTick(function() 
            try 
                resolve(fn());
             catch(e) 
                reject(e);
            
        );
    );


nextTick(function() 
     var a = null;
     a.b = 0;            // throw exception
).catch(function(e) 
     // catches exception here
);

当然,您也可以自己捕获异常并在本地处理它,但是如果没有承诺,就很难将错误传播回更高的级别:

 process.nextTick(function () 
     try 
         var a = null;
         a.b = 0;
      catch(e) 
          // handle exception here
     
 );

【讨论】:

以上是关于如何在 Promise 的回调中捕获未捕获的异常的主要内容,如果未能解决你的问题,请参考以下文章

尽管捕获异常,但未处理的 Promise Rejection

来自第 3 方静态库的回调中未捕获的异常

Promise.catch() 不会在 AngularJS 单元测试中捕获异常

swift - 如何处理未捕获的异常

全局捕获promise异常

js进阶五(js回调promisepromise嵌套异常处理jquery使用promise)