I have the following code:
const request = require('request-promise');
request(validateEmailOptions).then(function(result) {
if (result.valid) {
request(createUserOptions).then(function (response) {
if (response.updatePassword) {
request(modifyUserOptions).then(function (response) {
return res.redirect('/signin');
}).catch(function(error) {
return res.redirect('/error');
});
}
}).catch(function(error) {
return res.redirect('/error');
});
} else {
return res.redirect('/error');
}
})
.catch(function (reason) {
return res.redirect('/error');
});
Basically, it's a chain of request call, each one based on the result of the previous call. The problem is that I have many more lines in each condition and as a result, my code is bloated and hard to read and follow. I want to know if there is a better way to write the call chain using request-promises or simply request and bluebird.
You can unnest the promises. Think that this:
f(a).then(function(a) {
return g(b).then(function(b) {
return h(c)
})
})
Is the same as:
f(a).then(function(a) {
return g(b)
}).then(function(b) {
return h(c)
})
I would recommend failing as early as possible, that means handling the error condition first, and having meaningful error messages to be able to log them if need be. Finally, you can propagate the error and handle it in a single catch. To put it in context in your code:
request(validateEmailOptions).then(function(result) {
if (!result.valid) {
throw new Error('Result is not valid');
}
return request(createUserOptions);
}).then(function(response) {
if (!response.updatePassword) {
throw new Error('Password is not updated');
}
return request(modifyUserOptions);
}).then(function(response) {
return res.redirect('/signin');
}).catch(function(error) {
// you may want to log the error here
return res.redirect('/error');
});
Related
(I'm a beginner in JavaScript and have doubts in understanding javascript)
What my functions does?
Used Axios to get request and response from api in all three methods and log the status
This is implemented in three variants (callback,closure,promise)
My Understanding:
Legibility and readability is better in the below order:
Promise > Closures > Callback
//Callback
onMakeApiCallback() {
this.getData((response) => {
console.log("data callback success", response)
}, (error) => {
console.log("error is", error)
})
}
getData(onApiSuccess, onApiFail) {
axios.get("https://rallycoding.herokuapp.com/api/music_albums")
.then(function(response,error) {
if(response.data[3].title === "Red") {
onApiSuccess(response)
} else {
onApiFail(error)
}
})
}
The above is done using callback where i have sent a function as parameter to another function. I found this method to be complex when compared to other two.
//Closure
onMakeApiClosure() {
axios.get("https://rallycoding.herokuapp.com/api/music_albums")
.then(function(response,error) {
function innerfunction(response,error) {
if(response) {
console.log("success")
} else {
console.log("fail",error)
}
}
return innerfunction(response,error)
})
}
The above is done using Closure.Function within a Function
// Promise
onMakeApiPromise() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(function(response,error) {
console.log("1", response.data[3].title)
if(response.data[3].title === "Red") {
console.log("data is success", response)
} else if(error) {
console.log("error is ", error)
} else {
console.log("not equal")
}
})
}
When to use what?
Is there any other difference related to performance or any other traits among these three?
Links to understand
Closures
Callbacks
Promises
to understand promises u need to first get grip of asynchronous js.
I've only recently looked at promises (JS not being my forte) and I'm not sure what the proper way to do this is. Promises are supposed to prevent right-drifting code but when I end up with somewhat complex logic I end up nested far too deep anyway, so I'm convinced I'm doing it wrong.
If I'm returning both successes and failures as json values, and I want to handle malformed json as well, I immediately think to do something like this:
fetch('json').then(function (result) {
return result.json();
}).catch(function (result) {
console.error("Json parse failed!");
console.error(result.text);
}).then(function (wat) {
// if (!result.ok) { throw...
}).catch(function (wat) {
// Catch http error codes and log the json.errormessage
});
Of course, this won't work. This is stereotypical synchronous code. But it's the first thing that comes to mind. Problems I can see:
How do I get both the response and the json output?
How do I get separate control flow for errors and successes?
How do I catch a json parse error on both types of response?
My best attempt involves nesting to the point where I might as well be using callbacks, and it doesn't work in the end because I still haven't solved any of the above problems:
fetch('json').then(function (response) {
if (!response.ok) {
throw response;
}
}).then(
function (response) {
response.json().then(function (data) {
console.log(data);
});
},
function (response) {
response.json().then(function (data) {
console.error(data.errormessage);
});
}
).catch(function () {
console.error("Json parse failed!");
// Where's my response????
});
What's the "Right" way to do this? (Or at least less wrong)
If you want to call response.json() anyway (for successful and failed response) and want to use the response together will the response data. Use Promise.all:
fetch('json')
.then(response => Promise.all([response, response.json()]))
.then(([response, data]) => {
if (!response.ok) {
console.error(data.errormessage);
} else {
console.log(data);
}
})
.catch(err => {
if (/* if http error */) {
console.error('Http error');
} else if (/* if json parse error */)
console.error('Json parse failed');
} else {
console.error('Unknown error: ' + err);
}
});
You shouldn't use exceptions for control flow in Promises any more than you should when not using Promises. That's why fetch itself doesn't just reject the promise for status codes other than 200.
Here's one suggestion, but the answer will necessarily depend on your specific needs.
fetch('json').then(function (response) {
if (!response.ok) {
response.json().then(function (data) {
console.error(data.errorMessage);
});
return ...;
}
return response.json().catch(function () {
console.error("Json parse failed!");
return ...;
});
}).catch(function (e) {
console.error(e);
return ...;
});
1) I have a specific implementation where I want to adhere to the DRY principles.
The structure of both the methods is almost exactly the same. I am wondering if this is a way not to repeat the implementation:
addCardToExistingCustomer(cardDetail){
PaymentUtil.stripeCreateCardToken(cardDetail).then((cardTokenResult)=>{
if(cardTokenResult.error){
console.log("There was an error with the card!");
} else {
PaymentUtil.addCardToExistingCustomer(cardTokenResult.id).then((card) =>{
});
}
});
}
addCardToNewCustomer(cardDetail){
this.stripeCreateCardToken(cardDetail).then((cardTokenResult)=>{
if(cardTokenResult.error){
console.log("There was an error with the card!");
} else {
console.log("Successfully created card token");
PaymentUtil.stripeCreateCustomer(cardTokenResult.id)
}
});
}
2) Is this the best way to chain promises ? Specifically how should you handle exceptions from the promises in the chain which aren't the last element of the chain.
Say for example promise getStripeCustomerId rejected. How should you handle the the rejection.
addCardToExistingCustomer(cardTokenResultId){
return this.getStripeCustomerId(userDetail).then((customerId) => {
return this.removeAllExistingCards(userDetail).then(()=>{
return Stripe.addCardToCustomer(cardTokenResultId,customerId);
});
});
},
getStripeCustomerId(userDetail){
return FirebaseRESTUtil.getStripeCustomer(userDetail.username)
.then((fbStripe) => (fbStripe.customerId));
},
1- This way can be better.. It will use promises chains to work on data.
getCardTokenResult(cardDetail) {
return PaymentUtil.stripeCreateCardToken(cardDetail)
.then((cardTokenResult) => {
if(cardTokenResult.error){
return Promise.reject('There was an error with the card!!');
} else {
return cardTokenResult;
}
})
.catch((error) => console.log(error)):
}
addCardToExistingCustomer(cardDetail){
return getCardTokenResult(cardDetail)
.then((cardTokenResult) => {
PaymentUtil.addCardToExistingCustomer(cardTokenResult.id).then((card) =>{
// do something
});
});
}
addCardToNewCustomer(cardDetail){
return getCardTokenResult(cardDetail)
.then((cardTokenResult) => {
PaymentUtil.stripeCreateCustomer(cardTokenResult.id);
});
}
2- You can use catch to get errors on Promises chain. You can look the code above. I added catch to get cardtokenresult error. You can continue same way on chain to get other errors.
I noticed that you're checking for errors in the first argument of your then. I'm pretty sure this is incorrect as Stripe does not return HTTP 200 status on errors.
Having said that, I like to flatten chained promises instead of nesting them because I find that it makes the code easier to maintain and read:
addCardToExistingCustomer(cardTokenResultId) {
return this.getStripeCustomerId(userDetail).then((customerId) => {
return this.removeAllExistingCards(userDetail); // returns a promise
}).then(() => {
return Stripe.addCardToCustomer(cardTokenResultId,customerId); // returns a promise
});
},
Now any errors will bubble up to the main outer promise, so you can check for errors by
addCardToExistingCustomer(myId).then(() => {
console.log('success!');
}, (error) => {
console.log(error);
});
Here is what my code looks like:
return request.app.currentProject().then(function(project) {
return project.prs().query({
where: {id: request.params.prId}
}).fetchOne().then(function(pr) {
if (!pr) { return reply(Boom.notFound()); }
pr.destroy().then(function(model) {
return reply().code(204);
}).catch(function(err) {
return reply(Boom.badRequest(err));
});
}).catch(function(err) {
return reply(Boom.badRequest(err));
});
}).catch(function(err) {
return reply(Boom.badRequest(err));
});
Right now, in the code above, I have to catch each promise individually. Is there anyway to chain them so the errors bubble up without having to catch each promise individually?
Update
return request.app.currentProject().then(function(project) {
return project.prs().query({
where: {id: request.params.prId}
}).fetchOne();
}).then(function(pr) {
return pr.destroy();
}).catch(function(err) {
return reply(Boom.badRequest(err));
});
Promise errors bubble up automatically; you don't need to do anything.
Just remove all error handlers except at the end of the chain.
For more detailed guidelines for error handling, see my blog.
I am trying to write a promise function using Bluebird library for nodejs. I want to return 2 variables from my function.
I want the first function to return immediately and the second to complete its own promise chain before returning.
function mainfunction() {
return callHelperfunction()
.then(function (data) {
//do something with data
//send 200 Ok to user
})
.then(function (data2) {
//wait for response from startthisfunction here
})
.catch(function (err) {
//handle errors
});
}
function callHelperfunction() {
return anotherHelperFunction()
.then(function (data) {
return data;
return startthisfunction(data)
.then(function () {
//do something more!
})
});
}
Just like regular functions only have one return value, similarly promises only resolve with one value since it's the same analogy.
Just like with regular functions, you can return a composite value from a promise, you can also consume it using .spread for ease if you return an array:
Promise.resolve().then(function(el){
return [Promise.resolve(1), Promise.delay(1000).return(2));
}).spread(function(val1, val2){
// two values can be accessed here
console.log(val1, val2); // 1, 2
});
The only thing that appears to be wrong is the expectation that do something with data; send 200 Ok to user; should be performed in mainfunction(), part way through the promise chain in callHelperfunction().
This can be overcome in a number of ways. Here's a couple :
1. Move do something with data; send 200 Ok to user; into callHelperfunction()
function mainfunction() {
return callHelperfunction())
.catch(function (err) {
//handle errors
});
}
function callHelperfunction() {
return anotherHelperFunction()
.then(function (data1) {
//do something with data
//send 200 Ok to user
return startthisfunction(data1)
.then(function (data2) {
//wait for response from startthisfunction here
//do something more!
});
});
}
2. Dispense with callHelperfunction() altogether and do everything in mainfunction()
function mainfunction() {
return anotherHelperFunction()
.then(function (data1) {
//do something with data1
//send 200 Ok to user
return startthisfunction(data1);
})
.then(function (data2) {
//wait for response from startthisfunction here
})
.catch(function (err) {
//handle errors
});
}