可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This question already has answers here:
Closed 2 years ago.
We have a pattern for resolving promises in our Angular app that has served us well up until 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);
});
And here is how we are triggering the error in Karma:
resourceMock.get = function () {
var deferred = $q.defer();
deferred.reject(error);
return { $promise: deferred.promise };
};
Now, with the update to 1.6.0, Angular is suddenly complaining in our unit tests (in Karma) for rejected promises with a "Possibly unhandled rejection" error. But we are handling the rejection in the second function that calls our error service.
What exactly is Angular looking for here? How does it want us to "handle" the rejection?
回答1:
Try adding this code to your config. I had a similar issue once, and this workaround did the trick.
app.config(['$qProvider', function ($qProvider) {
$qProvider.errorOnUnhandledRejections(false);
}]);
回答2:
The code you show will handle a rejection that occurs before the call to .then
. In such situation, the 2nd callback you pass to .then
will be called, and the rejection will be handled.
However, when the promise on which you call .then
is successful, it calls the 1st callback. If this callback throws an exception or returns a rejected promise, this resulting rejection will not be handled, because the 2nd callback does not handle rejections in cause by the 1st. This is just how promise implementations compliant with the Promises/A+ specification work, and Angular promises are compliant.
You can illustrate this with the following code:
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")));
If you run it in Node, which also conforms to Promises/A+, you get:
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
回答3:
Found the issue by rolling back to Angular 1.5.9 and rerunning the test. It was a simple injection issue but Angular 1.6.0 superseded this by throwing the "Possibly Unhandled Rejection" error instead, obfuscating the actual error.
回答4:
The first option is simply to hide an error with disabling it by configuring errorOnUnhandledRejections
in $qProvider configuration as suggested Cengkuru Michael
BUT this will only switch off logging. The error itself will remain
The better solution in this case will be - handling a rejection with .catch(fn)
method:
resource.get().$promise
.then(function (response) {})
.catch(function (err) {});
LINKS:
- Promise
- Angular:
- Migrating Angular 1.5 to 1.6
- $http: remove deprecated callback methods: 'success()/error()'
回答5:
To avoid having to type additional .catch(function () {})
in your code in multiple places, you could add a decorator
to the $exceptionHandler
.
This is a more verbose option than the others but you only have to make the change in one place.
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);
};
}
};
回答6:
Please check the answer here:
Possibly unhandled rejection in Angular 1.6
This has been fixed with 316f60f and the fix is included in the v1.6.1 release.
回答7:
You could mask the problem by turning off errorOnUnhandledRejections, but the error says you're needing to "handle a possible rejection" so you just need to add a catch to your promise.
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);
});
Reference: https://github.com/angular-ui/ui-router/issues/2889
回答8:
I have observed the same behavior during test execution. It is strange that on production code works fine and fails only on tests.
Easy solution to make your tests happy is to add catch(angular.noop)
to your promise mock. In case of example above it should looks like this:
resourceMock.get = function () {
var deferred = $q.defer();
deferred.reject(error);
return { $promise: deferred.promise.catch(angular.noop) };
};
回答9:
I was also facing the same issue after updating to Angular 1.6.7 but when I looked into the code, error was thrown for $interval.cancel(interval);
for my case
My issue got resolved once I updated angular-mocks
to latest version(1.7.0).
回答10:
It may not be your speficic situation, but I had a similar problem.
In my case, I was using angular-i18n, and getting the locale dictionary asynchronously. The problem was that the json file it was getting was incorrectly indented (mixing spaces and tabs). The GET request didn't failed.
Correcting the indentation solved the problem.
回答11:
I had this same notice appear after making some changes. It turned out to be because I had changed between a single $http
request to multiple requests using angularjs $q
service.
I hadn't wrapped them in an array. e.g.
$q.all(request1, request2).then(...)
rather than
$q.all([request1, request2]).then(...)
I hope this might save somebody some time.