我有一个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);
};
})
根本没有帮助。在错误处理程序中,我已经收到“包装”错误。
答案 0 :(得分:17)
此问题已修复为fix($q): Add traceback to unhandled promise rejections -- Commit 316f60f,修正案已包含在v1.6.1 release中。
答案 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;
});
(记住我不是一位经验丰富的角色开发者)