I have two similiar functions foo and bar that looks like this
async function foo() {
try {
await postRequest()
} catch (error) {
throw error
}
async function bar() {
try {
await anotherReq()
} catch (error) {
// handle error
}
I want to call foo first, handle the error by calling bar, then handle eventual bar errors again.
So i tried to do this
try {
await foo();
} catch (error) {
try {
await bar()
} catch(error) {
// handle error
}
}
But it's obviously ugly because of the nesting.
Any workaround ?
What I usually do with async/await to avoid the nesting is to return tupels of [result, error] instead of try/catch blocks.
So in this case my code would look something like this:
async function foo() {
const response = await postRequest();
if (response.ok) {
return [response, null];
}
return [null, "error"];
}
async function bar() {
const response = await anotherReq();
if (response.ok) {
return [response, null];
}
return [null, "error"];
}
// call functions
const [res, err] = await foo();
if (err) {
const [res, err] = await bar();
}
you can do like this
try {
await foo();
await bar();
} catch (error) {
console.error(error)
}
Related
I have a nest.js application and these two methods below, on the first method I need to call two requests, but if the second fails it must give me an empty string and not throw an error. On the second method I passed an empty string when the request fail. I don't know if it's a good practice, but It's the only way I found to solve this problem.
async getData(): Promise<any> {
try {
const data1 = await this.service.getData1()
// if this request fail, I need it to get an empty string
const data2 = await this.service.getData2(data1.param)
} catch(error) {
throw Error(error)
}
}
async getData2(): Promise<string> {
try {
return await lastValueFrom(...some url to request);
} catch(error) {
// returning empty string and not throwing an error
return '';
}
}
First, you have to separate Data1 and Data2 functions
then Call Them From the getData Function
here is an Example
async getData(): Promise<any> {
try {
const data1 = await this.getData1()
if(data1 === '') {
const data2 = await this.getData2(param)
if(data2 === '') {
return 'no Data'
}
}
} catch(error) {
throw Error(error)
}
}
async getData1() {
try {
return await this.yourService.functionToGetData1()
} catch (error) {
// Return Empty String If Error
return ''
}
}
async getData2(param: any) {
try {
return await this.yourService.functionToGetData2()
} catch (error) {
// Return Empty String If Error
return ''
}
}
I think this is what you wanted to achieve - dont be afraid of using more than one try ... catch block
async getData(): Promise<any> {
let data;
try {
data = await this.service.getData1()
} catch(error) {
throw Error(error)
}
try {
// if this request fail, I need it to get an empty string
await this.service.getData2(data1.param)
} catch(error) {
return data;
}
return '';
}
Below is my function to return SQL query result.
function getPriorityList(operatorId) {
try {
const result = Api.getApisDetail(operatorId);
return result;
} catch (error) {
console.log(error);
}
}
you should wait for promise fulfillment
try this :
async function getPriorityList(operatorId) {
try {
const result = await Api.getApisDetail(operatorId);
return result;
} catch (error) {
console.log(error);
}
}
It appears that the promise implementation is incorrect in this case. Try something along these lines:
function getPriorityList(operatorId) {
Api.getApisDetail(operatorId).then((result) =>{
console.log(result);
return result;
}).catch((error)=>{
return error;
});
}
The "Api.getApisDetail" function must also return promise in this case.
I am trying to get the result from an async function but that async function can return either number or Error(if thrown by our code) in promise.
I tried to throw an exception from the catch block. But that I am getting some TSLint error that Expression Expected.
private async insertAppOrg(orgId): Promise<number> {
try {
return this.dbInstance.AppOrg.find({where: {orgId: orgId}})
.then(async (appOrgData) => {
if (appOrgData) {
return appOrgData.appOrgId;
} else {
return (await this.createAppOrg(orgId)); //return number
}
});
} catch (ex) {
return throw new ErrorFactory.DatabaseError(ex);
}
}
This function should return orgId(number) in case of success, else it should throw an Exception from the catch block.
return throw is syntax error because throw is a statement, not an expression.
Another problem is that an error from returned promise won't be handled with try..catch in async..await, it should be:
return await this.dbInstance.AppOrg.find(...).then(...)
There's no need to use then in async function because await is syntactic sugar for then:
private async insertAppOrg(orgId): Promise<number> {
try {
const appOrgData = await this.dbInstance.AppOrg.find({where: {orgId: orgId}});
if (appOrgData) {
return appOrgData.appOrgId;
} else {
return (await this.createAppOrg(orgId));
}
} catch (ex) {
throw new ErrorFactory.DatabaseError(ex);
}
}
You need to return the promise, and remove the try-catch block.
private async insertAppOrg(orgId: number): Promise<number> {
return this.dbInstance.AppOrg.find({ where: { orgId: orgId } })
.then(async (appOrgData: any) => {
if (appOrgData) {
return appOrgData.appOrgId;
} else {
return (await this.createAppOrg(orgId));
}
})
.catch((e: any) => {
throw new Error("This is an error")
});
}
I have this code:
async function getURL() {
try {
await fetch("http://www.blah.com");
return 0;
} catch (err) {
return err;
}
}
getURL().then( result => {
if (result === 0) console.log("success");
else console.log(result);
});
The fetch will fail and the error is logged to the console. How do I rework the code so it uses async and try/catch everywhere? That is, I'm looking to avoid doing getURL().then for the sake of consistency.
EDIT:
For those downvoting me, await getURL() won't work as it's invalid syntax.
EDIT2:
Tried this but it didn't catch the error:
async function getURL() {
return await fetch("http://www.blah.com");
}
let result = async function() {return await getURL();}
try {
result();
} catch (e) {
console.log(e);
}
You can wrap your whole code inside an instantly executed async function like this:
// service.js
async function getURL() {
return await fetch("http://www.blah.com");
}
// your.module.js
(async function() {
// do things...
try {
let result = await getURL();
} catch (e) {
console.log(e);
}
// do things...
res.send({});
});
Every time you need to catch an error from promise, either using new Promise, async-await or generator you need to use .then() or you can do something like this another async-await.
async function getURL() {
try {
await fetch("http://www.blah.com");
return 0; // EDIT: just returning value which is success
} catch (err) {
return err; // EDIT: returning value not rejecting a promise
}
}
async function main () {
try {
let result = await getURL();
if (result === 0) console.log("success");
console.log(result); // EDIT: error will be print.
}
catch (err) { // EDIT: getURL() never rejects so always success.
console.log(err);
}
});
main();
This situation doesn't really occurs as while our main function in server-side or client-side are async and handling this for us.
Like using express:
app.post('/api', async (req, res) => {
try {
let result = await getURL();
res.send(async);
}
catch(err) {
res.send(err);
}
});
EDIT: asyn-await doesn't reject or resolve a call, just return a value. thus must be used carefully.
function fetch(url) {
return new Promise( (resolve, reject) => {
let x = Math.floor(Math.random() * Math.floor(9) + 1);
// 50-50 resolve or reject
if(x%2===0) return resolve(false); //resolve with `false` statement
reject(true); // reject with `true` still a reject
});
}
async function getURL() {
try {
await fetch("http://www.blah.com");
return 0; // if fetch resolve
} catch (err) { //only if fetch reject
return err;
}
}
async function main () {
try {
let result = getURL();
if (result === 0) console.log("success"); //getURL never reject any call
console.log(result);
}
catch (err) { // getURL doesnt reject
console.log(err);
}
};
main();
I realize now async functions always return a promise. Even if you throw an error it still gets wrapped up into a promise. Therefore using try/catch won't help. This is how I ended up writing the code:
async function getURL() {
return await fetch("http://fake");
}
getURL().then( () => console.log("success")).catch( (e) => console.log(e));
I have the following code in my Node.js express app:
router.route('/user')
.post(async function(req, res) {
if(req.body.password === req.body.passwordConfirm) {
try {
var response = await userManager.addUser(req.body);
res.status(201).send();
} catch(err) {
logger.error('POST /user failed with error: '+err);
res.status(500).send({err:"something went wrong.."});
}
} else {
res.status(400).send({err:'passwords do not match'});
}
})
and userManager:
var userManager = function() {
this.addUser = async function(userobject) {
userobject.password_hash = await genHash(userobject.password_hash);
var user = new User(userobject);
return await user.save();
};
};
module.exports = userManager;
My question is: Will the try catch block in the route catch all errors thrown in addUser or will it only catch the ones that are thrown by user.save(), since that is the one that gets returned?
The answer is yes, it will catch all the errors inside try block and in all internal function calls.
async/await is just syntax sugar for promises. Thus if something is possible using promises then it is also possible using async/await.
For example both of the following code snippets are equivalent:
Using promises:
function bar() {
return Promise.reject(new Error('Uh oh!'));
}
function foo() {
return bar();
}
function main() {
return foo().catch(e => {
console.error(`Something went wrong: ${e.message}`);
});
}
main();
Using async/await:
async function bar() {
throw new Error('Uh oh!');
}
async function foo() {
await bar();
}
async function main() {
try {
await foo();
}
catch(e) {
console.error(`Something went wrong: ${e.message}`);
}
}
main();
In fact your code will not work since you don't use await on userManager.addUser.
It also forces you to use async on the parent function and that may break things up. Check express documentation (or just try if it works).
router.route('/user')
.post(async function(req, res) {
if(req.body.password === req.body.passwordConfirm) {
try {
var response = await userManager.addUser(req.body);
res.status(201).send();
} catch(err) {
logger.error('POST /user failed with error: '+err);
res.status(500).send({err:"something went wrong.."});
}
} else {
res.status(400).send({err:'passwords do not match'});
}
})