I have nested promise calls structure as follow:
validateUser()
.then(() => {
getUserInformation()
.then((userInformation) => {
Promise.all([
getUserDebitAccounts(userInformation),
getUserCreditAccounts(userInformation)
])
.then(([drAcc, crAcc]) => {
//do something
})
})
})
.catch(error => {
callback(error);
});
First of all is there a way to simplify these nested calls? As you can see they are structure as per dependency. So this is a most logical way I came up.
Second can I use catch at end to catch all the rejects on all above call. Do I have to add separate catch for each calls?
Third I want to write a mocha test what level of Promise mocking I have to do for these methods some outline will be helpful.
Any suggestion?
Yes, you can and should flatten your chain. To do that you'll need to return the inner promises from the then callbacks, which you will need anyway to make the single catch in the end work.
return validateUser()
.then(getUserInformation)
.then(userInformation =>
Promise.all([
getUserDebitAccounts(userInformation),
getUserCreditAccounts(userInformation)
])
).then(([drAcc, crAcc]) => {
// do something
return …;
})
.catch(error => {
console.error(error);
});
Related
I am trying to add a new user with firebase-admin and then to save a new document in a custom collection.
Sample code following:
admin.auth().createUser(user)
.then((record) => {
user.uid = record.uid;
userCollection.doc(record.uid).set({...user})
.then(writeResult => {
resolve();
})
.catch(reason => {
reject(reason)
});
})
.catch((err) => {
reject(err);
});
The problem is, if the userCollection.doc(record.uid).set({...user}) fails, I expect the nested catch (with reason as param) to be called. Instead, always the outer one is called (with err as param).
Is there something wrong with the SDK or am I doing something wrong?
Thank you
This is because you don't return the promise returned by userCollection.doc(record.uid).set() and therefore you don't return the promises returned by the subsequent then() and catch() methods. In other words you don't return the promises chain.
But, actually, you should chain your Promises as follows and avoid a then()/catch() pyramid.
admin
.auth().createUser(user)
.then((record) => {
user.uid = record.uid;
return userCollection
.doc(record.uid)
.set({ ...user })
})
.catch((err) => {
// Here you catch the potential errors of
// the createUser() AND set() methods
console.log(JSON.stringify(err));
});
More details here, here and here.
I'm new in promises and I'm currently trying to understand it. As I knew, Promise.all() has no function to check if one of the promises are rejected. So what I've tried is:
if ( Promise.all( promises ) ) {
console.log( "Everything is resolves!" );
} else {
console.log( "There is a rejected one!" )
}
But this seems to be not working. Is there any simple way to check this? I've found some questions with maps and tried it out but it looks wrong for my implementation.
Call .catch on the Promise call to see if at least one Promise rejects:
Promise.all(promises)
.then((results) => {
// ...
})
.catch((err) => {
// At least one of the Promises rejected (or an error was thrown inside the `.then`)
});
Promises.all( [promises array] ).then(function).catch(errorfunction)
you can do like this:
Promise.all([promises array])
.then((promisevalue) => console.log('returned'))
.catch(error => console.log(error.message));
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
I'm using .all method of popular library 'axios' for handling my ajax requests.
But how can I handle errors in case all requests got 404?
for example:
axios.all([
axios.get('http://some_url'),
axios.get('http://another_url'),
])
.then(axios.spread((someUrl, anotherUrl) => {
// ... boring stuff goes there
}))
.catch(() => {
//... error goes there
});
So, seems only one error has ben "catched".
How can I catch them all? Or maybe there any kinda .finally?
The problem (as you already know) is that you will get into catch block as soon as the first promise rejects, making it impossible to collect all failed responses in the same catch. However, you still can handle failed promises manually to aggregate errors and throw afterwards.
Check it this will work for you:
const promises = [
axios.get('http://some_url'),
axios.get('http://another_url'),
]
const promisesResolved = promises.map(promise => promise.catch(error => ({ error })))
function checkFailed (then) {
return function (responses) {
const someFailed = responses.some(response => response.error)
if (someFailed) {
throw responses
}
return then(responses)
}
}
axios.all(promisesResolved)
.then(checkFailed(([someUrl, anotherUrl]) => {
console.log('SUCCESS', someUrl, anotherUrl)
}))
.catch((err) => {
console.log('FAIL', err)
});
You will get into catch block if at least one of the promises fails. You can find one which one by checking err array of responses.
I don't think this is possible due to the fail fast behaviour of Promise.all. If any of your requests fail, they will automatically be the culprit and the result in the catch.
Promise.all([
Promise.reject(Error('1')),
Promise.reject(Error('2')),
Promise.reject(Error('3'))
]).then((results) => {
console.log(results)
}, (error) => {
console.log(error.message)
})
This resulting code will always print 1 as it is the first to fail.I think a similar feature was requested on the repo and they said it wasn't possible.
I was going to leave this as a comment but don't have a high enough reputation yet.
The solution from #dfsq did not work for me because it throws all requests when one has an error. I changed his code so every request either gets resolved or throws an error. #dfsq please review this answer if the code is correct, since I built it on your solution.
const promises = [
axios.get('http://some_url'),
axios.get('http://another_url'),
]
const promisesResolved = promises.map(promise => promise.catch(error => ({ error })))
function checkFailed (then) {
return function (responses) {
responses.forEach(response => {
if (response.error)
throw response;
return then(response);
})
}
}
axios.all(promisesResolved)
.then(checkFailed(response => {
console.log('SUCCESS', response)
}))
.catch((err) => {
console.log('FAIL', err)
});
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);
});
The motivation for this is to be able to catch all possible errors with the ending .catch, even ones that happen in initial synchronous code.
I want to start my promise chain like so:
const bbPromise = require('bluebird');
bbPromise.do(() => {
someTask(); // Could throw
return someVar.doSomeOtherTaskAsync();
})
.then((result) => {
// Do something with result
})
.catch((err) => {
console.log('err: ', err);
});
Is there a function that works like bbPromise.do function? bbPromise.resolve just gives me the whole lambda function that was passed in, unexecuted.
I know I could do something like this:
bbPromise.bind({}).then(() => {
someTask(); // Could throw
return someVar.doSomeOtherTaskAsync();
})
...
or even:
new bbPromise((resolve, reject) => {
someTask(); // Could throw
return someVar.doSomeOtherTaskAsync().then(resolve).catch(reject);
})
...
But these are a little indirect. Is there a good way to start a promise chain by just executing a function that could return a promise, and that has errors caught in the ending .catch?
It sounds like you're looking for Promise.try. Promise.resolve is appropriate when you have a value already and want to build a promise chain from it, but if you want to run some code that may throw, use Promise.try instead.
try takes and executes a function, dealing with any synchronous exception in the same manner as then would. You would end up with something like:
bbPromise.try(someTask).then(() => {
return someVar.doSomeOtherTaskAsync();
}).then((result) => {
// Do something with result
}).catch((err) => {
console.log('err: ', err);
});