31

我有一个AngularJS的代码:

service.doSomething()
  .then(function(result) {
      //do something with the result
  });

在 AngularJS 1.5.9 中,当我在以下.then()部分出现错误时:

service.doSomething()
  .then(function(result) {
      var x = null;
      var y = x.y;
      //do something with the result
  });

我收到明确的错误消息:

TypeError:无法读取 null 的属性“y”

但在 1.6 版中使用相同的代码,我得到了一个不同的错误:

可能未处理的拒绝:{} 未定义

我知道这与此更改.catch()有关,单个解决方案通过添加块非常简单:

service.doSomething()
  .then(function(result) {
      var x = null;
      var y = x.y;
      //do something with the result
  })
  .catch(console.error);

现在我又得到了我想要的:

TypeError:无法读取 null 的属性“y”

但是如何在不在.catch()每个地方添加块的情况下为整个应用程序获得相同的结果(更详细的错误)?

我通过添加以下内容测试了建议的解决方案以禁用此功能:

$qProvider.errorOnUnhandledRejections(false);

但这样情况就更糟了——我的控制台里什么都没有!错误在某处被吞没,根本没有记录。我不确定 AngularJS 1.6 或我的配置有问题。

您对如何从 1.5.9 版“恢复”日志记录行为有任何想法吗?

编辑:

添加自定义错误处理程序:

.factory('$exceptionHandler', function($log) {
  return function(exception, cause) {
    $log.warn(exception, cause);
  };
})

根本没有帮助。在错误处理程序中,我已经收到“包装”错误。

4

9 回答 9

20

这已通过fix($q): Add traceback to unhandled Promise Rejects - Commit 316f60f修复,该修复包含在v1.6.1 版本中。

于 2016-12-22T12:28:18.527 回答
17

第一个选项只是按照Cengkuru MichaelerrorOnUnhandledRejections的建议在 $qProvider 配置中隐藏禁用配置的错误:

app.config(['$qProvider', function ($qProvider) {
    $qProvider.errorOnUnhandledRejections(false);
}]);

但这只会关闭日志记录。错误本身将保留

在这种情况下,更好的解决方案是 - 使用以下方法处理拒绝.catch()

service.doSomething()
    .then(function (response) {})
    .catch(function (err) {});

有用的链接:

于 2017-07-28T08:28:25.303 回答
8

这些信息帮助我追踪(在我的情况下)是什么在创建承诺而不是添加错误处理程序。我发现它隐藏在问题#2889 "Possibly unhandled rejection with Angular 1.5.9"的讨论中。

要点是,$q在创建 Promise 时缓存堆栈跟踪的补丁,以便在触发错误时可以检索它。

为此,请插入以下代码来装饰$qAngular 应用顶部附近的某处:

// Decorate the $q service when app starts
app.decorator('$q', ["$delegate", function($delegate) {
  // Create a new promise object
  var promise = $delegate.when();

  // Access the `Promise` prototype (nonstandard, but works in Chrome)
  var proto = promise.__proto__;

  // Define a setter for `$$state` that creates a stacktrace 
  // (string) and assigns it as a property of the internal `$$state` object.
  Object.defineProperty(proto, '$$state', {
    enumerable: true,
    set: function(val) {
      val.stack = new Error().stack;
      this._$$state = val;
    },
    get: function() {
      return this._$$state;
    }
  });

  return $delegate;
}]);

然后在角度代码中搜索“可能未处理的拒绝”消息并在该行上放置一个断点。到达断点后,在控制台上打印出 的值toCheck.stack,您将看到如下内容:

>> toCheck.stack
"set@http://localhost:8000/js/dual-site.js:18:19
Promise@http://localhost:8000/js/angular.js:17008:22
then@http://localhost:8000/js/angular.js:17016:20
catch@http://localhost:8000/js/angular.js:17026:14
SyncStrategy.prototype.send@http://localhost:8000/js/angular-state-machine.js:436:24
StateMachine/this.send@http://localhost:8000/js/angular-state-machine.js:235:16

有问题的代码是调用 angular 的 catch/then 函数的框架。

于 2017-10-18T16:59:24.540 回答
8

我通过将 angular-ui-router 升级到 0.3.2 解决了版本 1.6.1 的相同问题。

于 2017-01-09T11:29:16.327 回答
4

还有另一种情况,向finally()承诺添加处理程序会产生错误: http: //plnkr.co/edit/eT834BkIEooAMvrVcLDe

因为finally()创建了一个新的 Promise 并调用它的解析器。(在拒绝案例中拒绝第二个)

我已经在 plnkr 中进行了修复,但看起来不太好。

于 2017-01-13T16:11:48.047 回答
3

当 angular-ui-router (ui-sref) 使用 angular ver1.6.1 处理被拒绝的承诺时,我得到了相同的未处理拒绝错误,并且默认情况下启用此功能。

对于任何想要解决方法的人(但不推荐),您可以像这样在全局范围内使未处理的承诺拒绝保持沉默 -</p>

app.config(['$qProvider', function ($qProvider) { $qProvider.errorOnUnhandledRejections(false); }]);

于 2017-01-18T06:20:33.110 回答
1

我已经通过在 catch 块中添加一个默认值来解决这个错误,例如:

service.doSomething()
    .then(function(response) {
        var x = null;
        var y = x.y;
    }).catch(function(error) {
        var y = 0;
    });

(算上我不是经验丰富的 Angular 开发人员)

于 2017-07-16T14:49:37.077 回答
0

errorOnUnhandledRejections(false); 对我来说不是一个决议。

您确实需要定义一个异常处理程序......但是......将它包装在一个超时函数中:这将强制抛出原始异常/堆栈跟踪。

要使错误在 Web 控制台中显示为错误,如您最初的预期:

ng.factory('$exceptionHandler', function($log) {
  return function(exception, cause) {
    // do some some stuff...
    setTimeout(function(){
      // throw the original exception (with correct line #'s etc)
      throw exception;
    })
  };
});

这是超时技巧: 为什么我不能在 Promise.catch 处理程序中抛出?

于 2017-05-10T22:02:11.960 回答
0

即使在我的 httpErrorInterceptor 中使用版本 1.6.1,我也有问题,对于一个用例,如果我的 api 返回 404,我必须尝试使用​​其他数据的另一个请求......所以在这种情况下,我只拒绝请求并且角度抛出未处理的拒绝错误...

我安装了 1.5.9,现在没有更多错误了!

于 2017-01-05T08:58:47.530 回答