I'm doing some HTTP calls in Node.js and want to examine whether or not the request failed or not - by this I mean that an error is not necessarily considered a "failure condition", but that I want to execute some business logic based on that. I have something similar to the following code (though obviously this is contrived since I simplified it):
let p = new Promise(function(resolve, reject) {
// In the real implementation this would make an HTTP request.
// The Promise resolution is either a response object or an Error passed to the `error` event.
// The error doesn't reject because the value I'm actually interested in getting is not the response, but whether the HTTP call succeeded or not.
Math.random() <= 0.5 ? resolve({ statusCode: 200 }) : resolve(new Error());
});
p.then(ret => { if (ret instanceof Error) return false; }) // This line should resolve the promise
.then(/* Handle HTTP call success */);
Basically I want to say, "if I resolved to an error object, just bail out and return false. Otherwise assert some more stuff on the response object and maybe return true, maybe return false."
How can I resolve the promise early and not execute the rest of the chain? Am I thinking about this all wrong? I'm not rejecting the promise if the HTTP call errors because AFAICT you can't get a value out of .catch() (this promise eventually gets passed to Promise.all) in the same way you can with .then(), but I could be wrong.
I'm on Bluebird, FWIW, so feel free to use extra stuff from them.
You can get values out of a catch(), just return them, as stated on the docs:
By not returning a rejected value or throwing from a catch, you "recover from failure" and continue the chain
That would be the best implementation ;)
Just don't use a chain here, but only a single handler:
p.then(ret => {
if (ret instanceof Error) return false; // This line will resolve the promise
/* else handle HTTP call success, and return true/false or another promise for it */
});
Related
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Handling a rejected promise too early has consequences further down the promise chain.
What kind of consequences can be there? In which cases should early handling of rejections be avoided and in which cases should early handling of rejections be preferred?
The critical part to understand is that catch() also returns a promise.
Consider the following example. Since the intermediate catch has no return BUT catch() itself returns a promise, the final catch never fires and the final then() does ... receiving a result of undefined from the prior catch() promise
const func = (val) => {
return new Promise((resolve,reject)=> {
// not really asynchronous, only contrived for demo
val === 1 ? resolve(val) : reject('Oooops')
}).catch(err=> {console.log('Err in func catch:', err)})
}
func(200).then(res=> console.log('Then res=', res))// receives undefined from prior catch
.catch(err=> console.log('Never gets called'))
So you could do several things differently here depending on preferred logic.
You could return a different expected value from the intermediate catch and look for that in the final then, or return another rejected promise or thrown error to be caught in the final catch().
Or...don't use the middle catch at all if it serves no value intercepting it.
Example use case for using the intermediate catch would be:
A map() of request urls passed through a function that returns the request promise back to your map array but you are OK if not all succeed.
Without the intermediate catch intercepting, the whole chain would break at first bad request. Instead you can return something from intermediate catch that you filter out in a Promise.all().then()
I have one array of promises that each one execute a code that can have a javascript error and break the script. I need to check for each promise and catch any error. The problem is that the promise has timeout functions inside. Is there anyway to solve this?
Example code:
function apiRequest(url,customError) {
return new Promise(function (resolve, reject) {
if(customError) {
setTimeout(() => {
//Force error
var ar = url.asdasd.eadasd;
ar = ar.split('123')
},3000)
}
if (url) {
return resolve(url);
} else {
return reject('apiRequest failed!');
}
})
.catch(function(err){
return 'error on javascript code';
});
}
var p1 = apiRequest('urlOne',true);
var p2 = apiRequest(false,false);
var p3 = apiRequest('urlThree');
Promise.all([p1, p2, p3])
.then(function(res){
console.log('Promise.all', res);
}, error => {
console.log('Error on reject')
})
.catch(function(err){
console.error('err', err);
});
Result:
Promise.all [ 'urlOne', 'error on javascript code', 'urlThree' ]
var ar = url.asdasd.eadasd;
TypeError: Cannot read property 'eadasd' of undefined
If there is an error inside each promise, my code can catch it but if there is a timeout and the error happends after the promise finish I cant catch it and my code breaks, is there anyway to catch this error?
Is there any way to check error in each Promise in promise.all when there is a promise error?
By design, Promise.all() resolves when ALL promises you passed it have resolved or it rejects when any single promise in it rejects. It does not, by design, wait for all promises to resolve or reject and then give you all the results whether they resolved or rejected.
Functionality like that is typically named something like Promise.settle() and you can fairly easily build that type of functionality by just adding a .catch() handler to each promise you pass Promise.all() so that instead of rejecting, it resolves, but with a value that you can later tell that it actually rejected.
You can see several various implementations of .settle() type functionality in this answer:
ES6 Promise.all() error handle - Is .settle() needed?
If there is an error inside each promise, my code can catch it but if there is a timeout and the error happends after the promise finish I cant catch it and my code breaks, is there anyway to catch this error?
The way you have structured your setTimeout(), it is not connected at all to the promise that it is inside of. If you want them connected, then you have to wait to resolve until after the timeout is done and then, and only then, can you know if you should resolve or reject.
Since the code you show inside your setTimeout() looks like pseudo-code (that doesn't actually do anything yet), it's hard for us to see exactly what the point of the setTimeout() is to know exactly what you are trying to achieve and thus what a good suggestion would be.
This answer about using setTimeout() as part of a promise chain might be relevant:
using setTimeout on promise chain.
In that case, the timer is inserted into the promise chain so that things are sequenced before it and after it. As you show it now, it's a completely separate parallel path of execution that has no connection at all to your promise chain.
If all you're trying to do with the setTimeout() is to invoke a timeout if your api request does not return before the timer fires, then you can likely implement that by just calling reject() inside the setTimeout(). If the api request has already completed and already called resolve(), then calling reject() will do nothing at that point. If the api request has not yet finished, then calling reject() will reject the host promise.
I have been writing NodeJS code for quite some time now, and seen different techniques implemented by people. My question is weather it is considered best practice having a function that as a signature returns a Promise, throw directly when parameter assertion fails.
So you think we should do this? :
Throw sync way
function asyncPromise(param) {
assert(param, 'Missing required parameter');
// Param ok
return Promise.resolve(param);
}
OR this ? :
Rejected Promise
function rejectPromise(param) {
if (typeof param === 'undefined') {
return Promise.reject(new Error('Missing required parameter'));
}
// Param valid
return Promise.resolve(value);
}
My gut is telling me to go for the first way of directly throwing since wrong parameter input should be considered as something that should not continue, however when a function has a signature of returning a Promise, the caller expects a .catch handling of an error, and will miss the error if thrown directly.
What is your opinion?
Maybe the problem is that you ask about asynchronous promises but use synchronous code example.
Correct relevant code should look something like this:
/**
* #return Promise Resolved when a value is accepted, rejected otherwise.
* #throw AssertionException When no parameter is given.
*/
function asyncPromise(param) {
assert(param, 'Missing required parameter');
var promise = new Promise(param);
something.process(promise); //start asynchronous process
return Promise;
}
//somewhere else while processing
try {
doSomething();
} catch (Exception err) {
promise.reject(err);
}
//somewhere else after processing is done
if (success) {
promise.resolve(result);
}
else {
promise.reject(error);
}
In this code there are two places where an error can happen: A) in the asyncPromise() which is synchronous error and can be safely handled by throwing an Exception and B) the processing where throwing an Exception would stop the processing but would not return any reply into the original function rendering the code frozen. In such case you must reject the promise instead of throwing an exception.
Solving the case A) by either rejecting the promise or throwing an exception should depend on what is the cause of the problem: If due to the problem you cannot create or process the promise (or something related to it) then it should return an exception. If on other hand you can safely create the promise but a problem arise while you try to start the processing, then it should reject the promise. Also good reason to reject the promise is when you realize there is no reason to start the process (e.g. when you already tried and failed).
Also note that the function clearly states that it returns a Promise but can throw an Exception if the parameter is not defined. That way everyone knows what to expect and how to use it.
I am a bit confused about what the statement
return $q.reject(response);
does inside the responseError interceptor.
I have gone through this article on webdeveasy and one on angular docs but they haven't helped.
Here is my code (for reference):
(function () {
"use strict";
angular.module('xyz').factory('errorResponseInterceptor', ['$q', 'toaster', function ($q, toaster) {
return {
...
...
...
responseError: function (response) {
...
...
//some logic here
...
...
if (response.status == 500) {
toaster.error({ title: "", body: response.statusText });
return $q.reject(response);//what does this statement does and why do we need to put it here?
}
return response;
}
};
}]);
}());
My Question is:
Why do we need to write return $q.reject(response)?
How does that line affect the angular app (what does it do)?
The $q object in Angular allows us to define a promise and handle the behaviour associated with a promise. An example of how we might do this is:
var q = $q.defer()
//do something
if(success){
q.resolve()
} else {
q.reject()
}
return q
What we are doing here is defining a promise object and assigning it to the variable q. Then we perform some operation and use the result of that to determine whether the promise returns successfully or not. Calling .resolve() on the promise object is indicative of the fact that the promise has returned correctly. By the same token calling .reject() on the promise is indicative of the fact that is has failed.
If we consider how we actually use a promise:
SomeFactory.getSomething().then(function(data){
//gets called if promise resolves
}, function(error){
//gets called if promise rejected
}
So in the example you have provided, we are checking to see if the response has a 500 error code, and if it does, we are rejecting the promise thus allowing us to handle the error.
In a responseError interceptor you have two choices with regards to what you return. If you return $q.reject(response) you are continuing the error handling chain of events. If you return anything else (generally a new promise or a response) you are indicating that the error has been recovered from and should be treated as a success.
With regards to your two points:
1- You need to write that line to indicate that the response should still be considered an error.
2- The effect on the angular app is that the error callback will be called instead of the success callback.
I have a function loadItems() that loads something async, and then fails or succeeds. Both fail and success callbacks must do something in the library, and then pass it on to the implementer, which can choose to implement fail, or success, or both, or none.
The problem I now have is if the library implements both the success and fail handler, it will always return a new promise that resolves to success.
This is what I have:
// The library:
function loadItems() {
return store.get('todo').then(function(rsp) {
// Save these locally
items = rsp.value || [];
}, function(rsp) {
// Do nothing, but let the user know
alert(rsp.error);
});
}
store.get('todo') (from yet another library) returns a promise. loadItems() has no control over it.
// The library implementer:
function init() {
loadItems().then(showItems);
}
What I want, and expected to happen:
loadItems() runs the async code from the library (store.get())
It implements success and fail because they have mandatory actions
It passes the success/failure on to the implementer
The implementer only implements success, because it doesn't care about errors, because the library handled it
So it uses .then(onSuccess) to 'add another success callback'
What happens instead (with an error):
The library's failure callback is executed
A new promise is passed on to the implementer
The new promise always resolves with success
The implementer's success callback is fired, with broken result, because the library's success callback didn't fire
Are Promises seriously too cool to have multiple, sync success handlers??
I can imagine even the source library (that defines store.get()) wants to handle the error (for logging sneakily), and then pass success/failure on.
My 'solutions':
Have loadItems()' failure callback throw an error. Unfortunately, that means init() has to catch it (or the browser whines about it). Not cool.
Use a simple callback to talk back to init(), instead of a promise, which only fires after a success. That's not good, because init() might choose to handle the error some day.
I'm sure I'm doing something wrong, but I don't see it.
If you want to have a reject handler to do something based on the error, but want the returned promise to still be rejected, you just rethrow the error (or return a rejected promise) after your reject handling code. This will allow the reject to propagate back through the returned promise.
// The library:
function loadItems() {
return store.get('todo').then(function(rsp) {
// Save these locally
items = rsp.value || [];
}, function(rsp) {
// Do nothing, but let the user know
alert(rsp.error);
// rethrow the error so the returned promise will still be rejected
throw(rsp);
});
}
Supplying a reject handler that does not throw or return a rejected promise tells the promise system that you have "handled" the error and the return value of your reject handler becomes the new fulfilled value of the promise. So, if you want the promise to "stay" rejected, but want to have a handler to do something based on the rejection (logging the rejection is very common), then you have to either rethrow the error in your reject handler or return a rejected promise.
While this may initially seem counter-intuitive, it gives you the most flexibility because you can either completely handle the error and let the returned promise be resolved "successfully" OR you can choose to tell the promise system that you want to propagate an error and you can even choose which error you want that to be (it does not have to be the same error).
The part of your question about multiple success handlers is a bit confusing to me. You can easily have multiple success handlers with any promise:
var p = someFuncThatReturnsSuccessfulPromise();
p.then(someSuccessHandler);
p.then(someOtherSuccessHandler);
If p is a successfully resolved promise, then these two success handlers will both be called in the order they are attached and what happens in someSuccessHandler will have no impact on whether someOtherSuccessHandler is called or not. If the original promise is resolved successfully, then both handlers will always be called.
If you chain your success handlers, then it is a completely different use case. This is completely different:
var p = someFuncThatReturnsSuccessfulPromise();
p.then(someSuccessHandler).then(someOtherSuccessHandler);
Because the second .then() handler is not attached to p, but is attached to p.then(someSuccessHandler) which is a different promise whose outcome is potentially influenced by what happens in someSuccessHandler.
The code in your question is chained. You are returning:
return store.get().then(...)
So, when the caller then chains onto that, the full chain is:
return store.get().then(yourhandler).then(theirhandler)
In this way, yourhandler can influence the outcome that is passed to theirhandler.
In addition to my first recommendation of just rethrowing the error, you could also have done this:
// The library:
function loadItems() {
var p = store.get('todo');
p.then(function(rsp) {
// Save these locally
items = rsp.value || [];
}, function(rsp) {
// Do nothing, but let the user know
alert(rsp.error);
});
return p;
}
Here you ware making sure that your handlers don't affect what is being returned. This can be done if you don't have any async operations in your handlers and you aren't trying to change the resolved value or rejected error of the original store.get() promise. I generally don't recommend this because it is a cause for problems if your handlers are doing other async things or want to influence the return values, but it can also be used in appropriate circumstances.