Angular 1.6 中可能未处理的拒绝

Possibly unhandled rejection in Angular 1.6

我有一个代码 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: Cannot read property 'y' of null

但是在使用相同代码的 1.6 版本中,我遇到了不同的错误:

Possibly unhandled rejection: {} undefined

我知道这个跟this change有关,解决方案很简单,加.catch()块:

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

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

TypeError: Cannot read property 'y' of null

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

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

$qProvider.errorOnUnhandledRejections(false);

但情况更糟 - 我在控制台中没有任何东西!错误被吞没在某个地方,根本没有记录。我不确定 AngularJS 1.6 或我的配置是否有问题。

您是否知道如何 "restore" 从版本 1.5.9 开始记录行为?

编辑:

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

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

一点帮助也没有。在错误处理程序中,我已经收到 "wrapped" 错误。

此问题已通过 fix($q): Add traceback to unhandled promise rejections -- Commit 316f60f and the fix is included in the v1.6.1 release 解决。

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

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

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

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

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

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

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

对于任何想要解决方法的人(尽管不推荐),您可以像这样在全局范围内阻止未处理的承诺拒绝 —

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

errorOnUnhandledRejections(假);对我来说不是解决方案。

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

要使错误在 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;
    })
  };
});

这里是超时技巧: Why can I not throw inside a Promise.catch handler?

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

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

(考虑到我不是经验丰富的 angular 开发人员)

第一个选项只是按照建议 Cengkuru Michael:

在 $qProvider 配置中使用 disablinconfiguring errorOnUnhandledRejections 隐藏错误
app.config(['$qProvider', function ($qProvider) {
    $qProvider.errorOnUnhandledRejections(false);
}]);

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

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

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

有用的链接:

此信息帮助我追踪(在我的例子中)创建承诺而不是添加错误处理程序的内容。我发现它隐藏在问题 #2889 "Possibly unhandled rejection with Angular 1.5.9".

的讨论中

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

为此,请插入此代码以装饰 $q 靠近 angular 应用顶部的某个位置:

// 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;
}]);

然后在 angular 代码中搜索消息 "possibly unhandled rejection" 并在该行放置一个断点。当到达断点时,在控制台打印出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 函数的框架。