Detect Existence of Next Handler in Angular JavaScript Promise Chain

Given the following two examples of $resource :

 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: in example two, there is no error handler]

And an interceptor that is 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 $promise.then() resource example does not contain an error callback? If the callback exists as in exampleOne , then I want to reject, but if not as in exampleTwo , then I want to redirect to the error page, changing the conditional to something like:

 if (response.status === 400 && $q.unresolvedPromises.doIndeedExist()) { ... 

Why? Because only some situations in my project require handling 400 in a way that is convenient for the user, so I would like to eliminate many repeated error callbacks or place a list of unusual situations in the interceptor. I would like the interceptor to be able to decide based on the presence of another handler in the promise chain.

+6
source share
2 answers

Simply put, this is not possible ; you cannot determine whether someone will attach a handler at some point in the future in the same way you cannot tell if this will be caught externally or not when throw in a function. However, what you want to do can be done .

This 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 } 

First thing you can do

Simply put, in the first case:

  exampleOne.$promise.then(function (success) {}, function (error) {}); 

What you receive is a promise that is always fulfilled. However, in the second case, the promise may be rejected. Handling a reject using the reject handler is similar to catch in real code - once you process it, it will no longer be rejected.

Personally, I would not use the interceptor here, but rather use the resource, since this was more clear with the intention, you can wrap it in a function so that it does not need scope, but I like this idea less. Here is what I would 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 } 

Now, a short proof that this cannot be done.

We prove it for pleasure.

Say we are assigned the program code M, we create a new promise p and replace each return in M and throw in M using return p.catch(function(){}) , and also add a return p.catch(function(){}) , now the handler will be added to p if and only if M is executed. Thus, in the short given code M, we built a way to see if it stops based on the existence of a solution to the search problem if catch added to p - so this problem is at least as complex as the stop problem .

+2
source

Maybe you can delay the redirect with a zero timeout and allow the error handler, if one exists, to set the flag of the error object with which the error was made:

 var interceptor = ['$q', '$timeout', function ($q, $timeout) { function error(rejection) { return $q.reject(rejection).finally(function () { $timeout(function () { if (rejection.errorHandled === true) { alert('all is under control'); } else { alert("Houston we've got problems"); } }, 0); //zero timeout to execute function after all handlers in chain completed }); } return { 'responseError': error }; }]; var exampleOne = $resource('/path').save(objectOne); exampleOne.$promise.then(function (success) { }, function(error) { error.errorHandled = true; }); 
0
source

Source: https://habr.com/ru/post/973781/


All Articles