Given the following two $resource
examples:
var exampleOne = $resource('/path').save(objectOne);
exampleOne.$promise.then(function (success) {}, function (error) {});
var exampleTwo = $resource('/path').save(objectTwo);
exampleTwo.$promise.then(function (success) {});
[NOTE: Example two contains no error handler]
And an interceptor that sits below all $http
requests:
var interceptor = ['$location', '$q', function ($location, $q) {
function error(response) {
if (response.status === 400) {
return $q.reject(response);
}
else {
$location.path('/error/page');
}
return $q.reject(response);
}
return {
'responseError': error
};
}
$httpProvider.interceptors.push(interceptor);
How can I make the interceptor not reject when the example resources $promise.then()
contain no error callback? If the call back exists as in exampleOne
then I wish to reject, but if not as in exampleTwo
then I wish to redirect to the error page thus changing the conditional to something like:
if (response.status === 400 && $q.unresolvedPromises.doIndeedExist()) { ...
Why? Because only some situations in my project call for handling a 400
in a user friendly way, thus I'd like to eliminate many duplicate error callbacks or having to place a list of uncommon situations in the interceptor. I'd like the interceptor to be able to decide based on the presence of another handler in the promise chain.
Simply put it is impossible, you can't detect if someone will attach a handler in some point in the future just like you can't tell if when you throw
in a function it will be caught on the outside or not. However, what you want done can be done.
It is not a 'noob question', and it is very fundamental:
function foo()
throw new Error(); // I want to know if whoever is calling `foo`
// handles this error
}
Simply put in the first case:
exampleOne.$promise.then(function (success) {}, function (error) {});
What you get is a promise that is always fulfilled. However, in the second case the promise might be rejected. Handling a rejection with a rejection handler is like a catch
in real code - once you handle it it is no longer rejected.
Personally, I would not use an interceptor here, but rather a resource-using pattern since that's more clear with intent, you can wrap it in a function so it won't need a scope but I like that idea less. Here is what I'd do
attempt(function(){
return $resource('/path').save(objectTwo).$promise.
then(function (success) {});
});
function attempt(fn){
var res = fn();
res.catch(function(err){
// figure out what conditions you want here
// if the promise is rejected. In your case check for http errors
showModalScreen();
}
return res; // for chaining, catch handlers can still be added in the future, so
// this only detects `catch` on the function passed directly so
// we keep composability
}
Let's prove it for fun.
Let's say we are given the code of a program M, we create a new promise p
and replace every return
statement in M andthrow
statement in M with a return p.catch(function(){})
and also add a return p.catch(function(){})
, now a handler will be added to p
if and only if running M
ever terminates. So in short - given code M we have constructed a way to see if it halts based on an existence of a solution to the problem of finding if catch
is appended to p
- so this problem is at least as hard as the halting problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With