Why does my async js/nodejs function skip a big part? - javascript

So I call the following function:
async function sql_func(){
console.log('anothertest')
async () => {
console.log('third test')
try {
await sql.connect('heres the connection data')
const result = await sql.query`heres a query`
console.log(result)
} catch(err) {
console.log(err)
}
}
}
the first console log anothertest gets logged but the part inside the async () => {} just gets completly skipped. When debugging i see that it just jumps from the async() => { line straight to the closing bracket }
What am I doing wrong?

async function sql_func() {
console.log('anothertest')
await sql.connect('heres the connection data')
const result = await sql.query`heres a query`
console.log(result)
return result
}
In your example there is no need to define another function: async () => { }. This function is never called. Also async functions handles all promises and rejects when a one of the promises is rejected. The catch you can do at the main function level:
const result = await sql_func().catch(error => // do something)
// Or with try / catch
If you want a different error message (e.g.: hide the real error / stack trace):
async function sql_func() {
console.log('anothertest')
await sql.connect('heres the connection data').catch(error =>
Promise.reject('DB Connection error')
)
const result = await sql.query(`heres a query`).catch(error =>
Promise.reject('Query failed')
)
console.log(result)
return result
}

Related

Curry function with the first one as an async function isn't working

I'm trying to curry a function but when the first one is async it throws the error function1(...) is not a function, however if I pass the async function as the last one it works fine.
Can anyone tell me why this is happening? and how to properly make a curry function that starts with a async function?
Thanks to anyone who take the time.
//This one is throwing the error: function1(...) is not a function
async function function1(path) {
const fetchedElement = await fetchElement(path);
//(...)
return (msg) => {
console.log(msg);
};
}
function1('somepath.html')('my message');
//This one works fine, properly returning other function
function function2(path) {
return async (msg) => {
const fetchedElement = await fetchElement(path);
//(...)
console.log(msg);
};
}
function2('somepath.html')('my message');
It depends on when the async work needs to get done. If you want the currying process to do the async work, then you can't invoke the currying function synchronously:
curryingFunction(paramA)(paramB)
^ assumes curryingFunction is synchronous
Instead, use two statements by the caller, one to await the currying, the other to invoke...
const fetch = path => new Promise(resolve => setTimeout(() => {
console.log('fetched ' + path)
resolve()
}, 1000));
async function curryingFunction(path) {
const fetchedElement = await fetch(path);
return message => {
console.log(message);
}
}
async function someCaller() {
// await to get a curried function, then invoke it
let curried = await curryingFunction('some_path');
curried('some message');
}
someCaller()
On the other hand, you might not need to do the async work in order to get the curried function. You probably don't. In that case, you can make the currying function synchronous, but have it return an async function that does the async work.
As a result, you'll get to use the fn()() syntax that you're probably used to using...
const fetch = path => new Promise(resolve => setTimeout(() => {
console.log('fetched ' + path)
resolve()
}, 1000));
function curryingFunction(path) {
return async (message) => {
const fetchedElement = await fetch(path);
console.log(message);
}
}
async function someCaller() {
// here we can use the fn()() syntax that we're accustomed to
await curryingFunction('some path')('some message')
}
someCaller()
As the first function is async You need to await it first, then call the second parameter.
//This one is throwing the error: function1(...) is not a function
async function function1(path) {
const fetchedElement = await Promise.resolve(1);
//(...)
return (msg) => {
console.log(msg);
};
}
(async () => {
try {
(await function1('somepath.html'))('my message');
} catch(e) {
console.log(e)
}
})()

Try/Catch in mulitple awaits in express app

I am making a few database calls and I am using async/await and try/catch for error handling. I am struggling if I should have all of the db calls in one try/catch, or have multiple try/catch` blocks for each call.
I also have a few calls in callback fncs, I am not confident those calls will be caught in my catch block if I only have one try/catch. With that in mind, those calls have their own try catch block. Here is a working example:
exports.syncStaff = async function (req, res, next) {
// ShiftTask && Shift is a model from mongoose
try {
// DB CALL #1 --> Inside of Try/Catch Block
const shift = await Shift.findById(req.params.id);
// DB CALL #2 + 3 --> Two calls run in parallel --> Inside of Try/Catch Block
const [shiftTasks, shiftType] = await Promise.all([
ShiftTask.find({ group: shift.id }),
mongoose.model('ShiftType').findById(shift.type).populate('tasks').select('tasks')
]);
await Promise.all(shiftTasks.filter(st => !shiftType.workshops.find(type => type.id.toString() === st.task.toString() || st.status !== 'pending')).map(task => {
// DB CALL #4 --> Separate Try/Catch Block, is this needed?
try {
return ShiftTask.remove({ _id: task.id });
} catch (error) {
console.error(error);
next(error);
}
}));
await Promise.all(shiftType.workshops.filter(type => !shiftTasks.find(task => task.shift.toString() === type.id.toString())).map(type => {
try {
// DB CALL #5 -- Separate Try/Catch Block, is this needed?
return ShiftTask.create({
group: shift.id,
eventType: type.id
});
} catch (error) {
console.error(error);
next(error);
}
}));
return await res.status(201).json('still to be decided');
} catch (error) {
console.error(error);
next(error);
}
};
Are the try/catch blocks in db calls #4 and #5 necessary?
I don't think external try catch blocks are needed. If an error is thrown from somewhere, it can be caught from the block in the public container. I made an example like this. You can test the 2nd case specified in the code from the google chrome console.
let compPromise = new Promise(function(resolve, reject) {
resolve('Complete');
});
let errPromise = new Promise(function(resolve, reject) {
reject(new Error("Whoops promise reject!"))
});
let exec = async () => {
try {
let res1 = await compPromise;
console.log('res1', res1);
let [res2,res3] = await Promise.all([
compPromise,
compPromise
])
console.log('res2', res2);
console.log('res3', res3);
// In this case, reject will return from the promise and will catch it in the catch block.
await Promise.all([10, 20, 30].map((x) => x === 30 ? errPromise : compPromise))
// In this case, the parameter was deliberately sent as undefined and will still be caught in the catch block.
await Promise.all([undefined, 'Johnny', 'Alison'].map((x) => x.trim().includes("n") ? errPromise : compPromise))
} catch(err) {
console.log(err.toString());
}
}
exec()

Throwing errors in async await functions and catching from where it's called

How can we catch error from an async await function from where it's called?
For example, I have a React component which calls a async-await function imported from another module. When I use Promise.reject("An unknown has occurred"); in that function, so in my React component why can't I get the error in asyncAwaitFunction.catch((e)=>console.log(e))?
I even tried throw "An unknown occured", but it doesn't seem to work.
react component
const handleSubmit = async (e) => {
e.preventDefault();
add(formData, code)
.then(() => router.push("/dashboard/manage"))
.catch((e) => setError(e)); //I want error to be catched here
};
functions.js
export const addUser = async (details, code) => {
const isExist = await isUser(code);
if (!isExist) {
const add = db.batch(); //firebase batch write
add.set(userID(code), details); //Add details to databse
add.commit()
.catch((e)=> {
console.log(e); // error occurs confirmed
Promise.reject("Unknown error occurred"); //this does't get catched in component.
});
} else {
Promise.reject("Already Exists!");
}
};
A rejected Promise (either from a Promise that you constructed that rejected, or from a Promise.reject) will only be caught if:
a .catch is added onto the end of that Promise expression, or
that Promise expression is returned inside an async function or a .then, and the caller of the async function or after the .then callback, there's a .catch
So, you should change to something like:
export const addUser = async (details, code) => {
const isExist = await isUser(code);
if (isExist) {
return Promise.reject('Already Exists!');
}
const add = db.batch(); //firebase batch write
add.set(userID(code), details); //Add details to databse
return add.commit().catch((e) => {
console.log(e); // error occurs confirmed
return Promise.reject("Unknown error occurred");
});
};
But do you really need to log in the .commit().catch? If not, it'd be cleaner to just return the commit Promise and catch in the caller:
export const addUser = async (details, code) => {
const isExist = await isUser(code);
if (isExist) {
return Promise.reject('Already Exists!');
}
const add = db.batch(); //firebase batch write
add.set(userID(code), details); //Add details to databse
return add.commit();
};
A Promise that is awaited or returned from an async function will have its errors (or its resolve value) percolate up to the caller of the async function.

Javascript async function return then-catch promise?

Introduction
I am new in the world of javascript promises and I need to understand how they work correctly...
Until know I have been doing this in my code:
const handleRefresh = () => {
setIsRefreshing(true);
fetchUserData()
.then(async () => { <--------- Using then because I return a promise in fetchUserData
await fetchUserPosts(); <------- Using await here
setIsRefreshing(false);
}).catch(err => { <--------- This will catch the error I have thrown in the function fetchUserPosts or inside the then body
// TODO - Show error
setIsRefreshing(false);
console.log(err)
);
};
const fetchUserData = async () => { <------ async function
const { firebase } = props;
const userId = firebase.getCurrentUser().uid;
const documentRef = firebase.getDatabase().collection("users").doc(userId);
// Fetch all the user information
return documentRef <--------- Returning the promise here
.get()
.then((doc) => {
if (doc.exists) {
// Get all user data
const data = doc.data();
console.log(data);
setUserData(data);
}
})
.catch((err) => {
throw err; <----------- Throwing error
});
};
I don't know if I am doing anti patterns... But basically I need to know if this is a good way and if I am doing this correctly.
Questions
Do I have to declare the fetchUserData function as async to return a promise?
Can I use the async await in the then/catch body?
Can I do this?
const handleRefresh = async () => {
setIsRefreshing(true);
await fetchUserData()
.then(async () => { <--------- Using then because I return a promise in fetchUserData
await fetchUserPosts(); <------- Using await here
}).catch(err => { <--------- This will catch the error I have thrown in the function fetchUserPosts or inside the then body
// TODO - Show error
console.log(err)
);
setIsRefreshing(false);
};
I would really appreciate if someone guides me. Thanks.
the words async and await are only syntactic sugar for then and catch.
This:
fetchUserData()
.then(data => return data )
.catch(error => return error)
is equivalent to:
async function getUserData() {
const userData = await fetchUserData()
return userData
}
Here you are returning anything (success or error). If you want to treat the error here, just put a try/catch clause.
async function getUserData() {
try {
return await fetchUserData()
} catch (e) {
return e.message
}
}
Note that you can only use the await clause within an async function.
1.
Function can return Promise without being declared as async as long as you don't await inside it,
2.
You should not use async-await inside then, simply return a Promise and it'll be resolved in the following then,
3.
When using async-await syntax, Promises are awaited in a declarative way as demonstrated below:
const handleRefresh = async () => {
try
{
const a = await getA()
// pass the result to another Promise
const b = await getB(a)
const c = await getC(b)
} catch (error)
{
handleError(error)
}
};

Why I get pending from this function

async function test() {
const res = await fetch('https://www.easy-mock.com/mock/5c6d317e8d040716434d0a5b/reading/category/homeSmallCategory');
console.log(res) // data
return res;
}
console.log(test()) // PromiseĀ {<pending>}
setTimeout(() => {
console.log(test()) // PromiseĀ {<pending>}
})
Please parse it at the console.
How do I deal with this problem.I want the data processing in the test function .But it always return PromiseĀ {<pending>}.
And then I think that I can deal with it like this.
if (res instanceof Promise) {
res.then(data => res = data);
}
I put it at the end of the test.But it still not working.I console the Object.prototype.toString.call(res).And then I get [object Array].I realized that inside the function. The res is an array not matter what.But at the outside the res is not alike that. I know this is something about event loop.Thanks for your help.
async function test() {
const res = await fetch('https://www.easy-mock.com/mock/5c6d317e8d040716434d0a5b/reading/category/homeSmallCategory');
console.log(res) // data
return res;
}
console.log(test()) // Promise {<pending>}
That's simply because test is an async method and async method always return a Promise. So you either chain a .then or await test()
test().then(res => console.log(res))
or
const res = await test();
console.log(res)
Try this approach.
async function test() {
const res = await fetch('https://www.easy-mock.com/mock/5c6d317e8d040716434d0a5b/reading/category/homeSmallCategory');
return res;
}
test().then(ok => {console.log(ok)}, not_ok => {console.log(not_ok)});

Categories