我们在Angular应用程序中有一个解决承诺的模式,直到Angular 1.6.0为止我们一直很好:
resource.get().$promise
.then(function (response) {
// do something with the response
}, function (error) {
// pass the error the the error service
return errorService.handleError(error);
});
以下是我们如何在Karma中触发错误:
resourceMock.get = function () {
var deferred = $q.defer();
deferred.reject(error);
return { $promise: deferred.promise };
};
现在,随着1.6.0的更新,Angular突然在我们的单元测试中(在Karma中)抱怨被拒绝的承诺,其中包括"可能未处理的拒绝"错误。但我们正在处理调用错误服务的第二个函数中的拒绝。
Angular究竟在寻找什么?它是如何让我们处理"拒绝?
答案 0 :(得分:66)
尝试将此代码添加到您的配置中。我曾经遇到过类似的问题,而且这种解决方法可以解决问题。
app.config(['$qProvider', function ($qProvider) {
$qProvider.errorOnUnhandledRejections(false);
}]);
答案 1 :(得分:20)
您展示的代码将处理在调用.then
之前发生的拒绝。在这种情况下,您将调用传递给.then
的第二个回调,并将处理拒绝。
然而,当您致电.then
的承诺成功时,它会调用第一个回调。 如果此回调引发异常或返回被拒绝的承诺,则不会处理此结果拒绝,因为第二个回调不会处理第一个引起的拒绝。这就是承诺实现符合Promises/A+规范的工作方式,以及Angular承诺是否合规。
您可以使用以下代码说明这一点:
function handle(p) {
p.then(
() => {
// This is never caught.
throw new Error("bar");
},
(err) => {
console.log("rejected with", err);
});
}
handle(Promise.resolve(1));
// We do catch this rejection.
handle(Promise.reject(new Error("foo")));
如果你在Node中运行它,它也符合Promises / A +,你得到:
rejected with Error: foo
at Object.<anonymous> (/tmp/t10/test.js:12:23)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:394:7)
at startup (bootstrap_node.js:149:9)
at bootstrap_node.js:509:3
(node:17426) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: bar
答案 2 :(得分:18)
通过回滚到Angular 1.5.9并重新运行测试找到问题。这是一个简单的注入问题,但Angular 1.6.0通过抛出“可能未处理的拒绝”错误取代了这一点,混淆了实际的错误。
答案 3 :(得分:16)
第一个选项只是隐藏错误并通过在$ qProvider配置中配置errorOnUnhandledRejections
建议Cengkuru Michael
但是这只会关闭日志记录。错误本身将保持
在这种情况下, 更好的解决方案 - 使用.catch(fn)
方法处理拒绝:
resource.get().$promise
.then(function (response) {})
.catch(function (err) {});
LINKS:
答案 4 :(得分:4)
为避免在多个地方的代码中输入其他.catch(function () {})
,您可以向decorator
添加$exceptionHandler
。
这是一个比其他选项更冗长的选项,但您只需在一个地方进行更改。
angular
.module('app')
.config(configDecorators);
configDecorators.$inject = ["$provide"];
function configDecorators($provide) {
$provide.decorator("$exceptionHandler", exceptionHandler);
exceptionHandler.$inject = ['$delegate', '$injector'];
function exceptionHandler($delegate, $injector) {
return function (exception, cause) {
if ((exception.toString().toLowerCase()).includes("Possibly unhandled rejection".toLowerCase())) {
console.log(exception); /* optional to log the "Possibly unhandled rejection" */
return;
}
$delegate(exception, cause);
};
}
};
答案 5 :(得分:3)
答案 6 :(得分:3)
您可以通过关闭errorOnUnhandledRejections来掩盖问题,但错误表明您需要处理可能的拒绝问题&#34;所以你只需要为你的承诺添加一个捕获。
resource.get().$promise
.then(function (response) {
// do something with the response
}).catch(function (error)) {
// pass the error to the error service
return errorService.handleError(error);
});
答案 7 :(得分:2)
我在测试执行期间观察到了相同的行为。奇怪的是,生产代码工作正常并且仅在测试时失败。
让您的测试满意的简单解决方案是将catch(angular.noop)
添加到您的promise模拟中。如果是上面的例子,它应该是这样的:
resourceMock.get = function () {
var deferred = $q.defer();
deferred.reject(error);
return { $promise: deferred.promise.catch(angular.noop) };
};
答案 8 :(得分:2)
在更新到Angular 1.6.7后我也遇到了同样的问题但是当我查看代码时,typeof(MyList<>).GetMethod("Add").DeclaringType.GetGenericTypeDefinition()
为我的案例引发了错误
我将var instantiationListArgs = typeof(MyList<>).GetMethod("Add").DeclaringType.GetGenericArguments();
var myListArg = typeof(MyList<>).GetGenericArguments();
var listArgs = typeof(List<>).GetGenericArguments();
Console.WriteLine(myListArg[0] == instantiationListArgs[0]); // Will output true, List was instantiated for the T in MyList
Console.WriteLine(listArgs[0] == instantiationListArgs[0]); // Will be false. The generic argument is different then the T in the free List<>
更新为最新版本(1.7.0)后,我的问题得到了解决。
答案 9 :(得分:0)
这可能不是你的特殊情况,但我遇到了类似的问题。
在我的情况下,我使用angular-i18n,并异步获取语言环境字典。问题是它获得的json文件被错误缩进(混合空格和制表符)。 GET请求没有失败。
纠正缩进解决了问题。
答案 10 :(得分:0)
进行一些更改后,我也出现了同样的提示。原来是因为我已使用angularjs $http
服务将单个$q
请求更改为多个请求。
我没有将它们包装成阵列。例如
$q.all(request1, request2).then(...)
而不是
$q.all([request1, request2]).then(...)
我希望这可以节省一些时间。