在Angular 1.6中可能无法处理拒绝

时间:2016-12-22 10:56:17

标签: javascript angularjs angular-promise angular-providers angularjs-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:无法读取null的属性“y”

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

  

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

我知道这与this change有关,通过添加.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);
  };
})

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

9 个答案:

答案 0 :(得分:17)

答案 1 :(得分:15)

第一个选项只是隐藏错误,并按照建议Cengkuru Michael在$ qProvider配置中配置errorOnUnhandledRejections

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

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

在这种情况下,

更好的解决方案 - 使用.catch()方法处理拒绝:

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

有用的链接:

答案 2 :(得分:8)

我通过将angular-ui-router升级到0.3.2来修复版本1.6.1的相同问题。

答案 3 :(得分:4)

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

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

我在plnkr中修了一下,但看起来不太好。

答案 4 :(得分:4)

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

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

要做到这一点,请插入此代码以在角度应用顶部附近的某处装饰$q

// 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

违规代码是调用角度捕获/然后函数的框架。

答案 5 :(得分:3)

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

对于任何想要解决方法的人(不建议使用),你可以在全球范围内对未经处理的承诺拒绝做出沉默 -

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

答案 6 :(得分:0)

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

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

答案 7 :(得分:0)

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

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

要使错误在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?

答案 8 :(得分:0)

我通过在catch块中添加默认值来解决此错误,如:

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

(记住我不是一位经验丰富的角色开发者)