可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a code with AngularJS:
service.doSomething()
.then(function(result) {
//do something with the result
});
In AngularJS 1.5.9 when I have error in the .then()
section like:
service.doSomething()
.then(function(result) {
var x = null;
var y = x.y;
//do something with the result
});
I'm getting clear error message:
TypeError: Cannot read property 'y' of null
But in version 1.6 with the same code I'm getting a different error:
Possibly unhandled rejection: {} undefined
I know that this is related to this change, and the single solution is quite simple by adding .catch()
block:
service.doSomething()
.then(function(result) {
var x = null;
var y = x.y;
//do something with the result
})
.catch(console.error);
Now I again have what I want:
TypeError: Cannot read property 'y' of null
But how to obtain the same result (more detailed error) for entire application without adding .catch()
block in every single place?
I tested the suggested solution to disable this by adding:
$qProvider.errorOnUnhandledRejections(false);
But with this the situation is even worse - I do not have ANYTHING in the console! The error is swallowed somewhere and not logged at all. I'm not sure is it a problem with AngularJS 1.6 or with my configuration.
Do you have any ideas how to "restore" logging behavior from version 1.5.9?
EDIT:
Adding custom error handler:
.factory('$exceptionHandler', function($log) {
return function(exception, cause) {
$log.warn(exception, cause);
};
})
does not help at all. In the error handler I already receive the "wrapped" error.
回答1:
This has been fixed with fix($q): Add traceback to unhandled promise rejections -- Commit 316f60f and the fix is included in the v1.6.1 release.
回答2:
First option is simply to hide an error with disablinconfiguring errorOnUnhandledRejections
in $qProvider configuratio as suggested Cengkuru Michael:
app.config(['$qProvider', function ($qProvider) {
$qProvider.errorOnUnhandledRejections(false);
}]);
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()
method:
service.doSomething()
.then(function (response) {})
.catch(function (err) {});
Useful Links:
- Promise
- Migrating Angular 1.5 to 1.6
- $http: remove deprecated callback methods: 'success()/error()'
回答3:
I fixed the same problem with version 1.6.1 by upgrading angular-ui-router to 0.3.2.
回答4:
This information helped me to track down what (in my case) was creating the promise and not adding an error handler. I found it buried in the discussion of issue #2889 "Possibly unhandled rejection with Angular 1.5.9".
The gist, is, patch $q
to cache a stack-trace on creating promises, such that it can be retrieved when the error is triggered.
To do it, insert this code to decorate $q
somewhere near the top of your angular app:
// 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;
}]);
Then search the angular code for the message "possibly unhandled rejection" and put a breakpoint on that line. When the breakpoint is reached, print out the value of toCheck.stack
on the console, and you'll see something like this:
>> 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
The offending code is the frame calling angular's catch/then functions.
回答5:
There is another case, adding a finally()
handler to a promise generate the error:
http://plnkr.co/edit/eT834BkIEooAMvrVcLDe
Because finally()
creates a new promise and call the resolver on it. (Rejecting a 2nd one in a rejection case)
Ive put a fix in the plnkr but it doesn't look very good.
回答6:
I got same unhandled rejection error when a rejected promise is not handled by angular-ui-router (ui-sref) using angular ver1.6.1 & This feature is enabled by default.
For anyone that wants a workaround (not recommended, though), you can globally silence unhandled promise rejections like this —
app.config(['$qProvider', function ($qProvider) {
$qProvider.errorOnUnhandledRejections(false);
}]);
回答7:
I have the problem even with version 1.6.1 in my httpErrorInterceptor, for one usecase my if my api return 404 i have to try another request with other data... so in this case i only reject the request and angular throw the unhandled rejection error...
I install 1.5.9 and now there is no more error !
回答8:
errorOnUnhandledRejections(false); was not a resolution for me.
You do indeed need to define an exception handler... however... wrap it in a timeout function: this will force the original exception/stack trace to be thrown.
To make the error show up as an error in the web console, as you originally intended:
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;
})
};
});
Heres the timeout trick:
Why can I not throw inside a Promise.catch handler?
回答9:
I have solved this error by adding a default value in the catch block like:
service.doSomething()
.then(function(response) {
var x = null;
var y = x.y;
}).catch(function(error) {
var y = 0;
});
(take in count that I am not an experienced angular developer)