Javascript - .catch async callback - javascript

Is it an anti-pattern to use an async method for catching errors?
await something().catch(aysnc (err) => {
console.log(err);
await rollback();
});
I am doing this because I need to make sure that the rollback has been executed before letting the user execute the method again:
const method = async () => {
if(isExecuting.current) return;
isExecuting.current = true;
await something().catch(aysnc (err) => {
console.log(err);
await rollback(); <--- I NEED TO AWAIT THIS TOO
});
isExecuting.current = false;
}

you can do it more clearly using try and catch
const method = async() => {
if (isExecuting.current) return;
isExecuting.current = true;
try {
await something();
} catch (err) {
console.log(err);
await rollback();
}
isExecuting.current = false;
}

Related

How to return data from RabbitMQ consume function in nodejs?

I have consume function like this.
In this case when i put console.log() in consume callback function, i see messages coming from queue.
Function 1
async function consumeData() {
try {
const connection = await amqp.connect("amqp://localhost:5672");
const channel = await connection.createChannel();
await channel.assertQueue(queueName);
let consumedData;
channel.consume(queueName, (message) => {
consumedData = message.content.toString();
console.log(consumedData);
channel.ack(message);
});
} catch (error) {
console.log("Error", error);
}
}
But i dont wanna log this data. I wanna return and use it like this.
Function 2
async function consumeData() {
try {
const connection = await amqp.connect("amqp://localhost:5672");
const channel = await connection.createChannel();
await channel.assertQueue(queueName);
let consumedData;
channel.consume(queueName, (message) => {
consumedData = message.content.toString();
console.log(consumedData);
channel.ack(message);
});
return consumedData;
} catch (error) {
console.log("Error", error);
}
}
When i run function 2 i cant return any data. How can i return data from this consume function?
return it after trycatch
async function consumeData() {
var consumedData = {};
try {
const connection = await amqp.connect("amqp://localhost:5672");
const channel = await connection.createChannel();
await channel.assertQueue(queueName);
let consumedData;
channel.consume(queueName, (message) => {
consumedData = JSON.parse(message.content.toString());
channel.ack(message);
});
} catch (error) {
console.log("Error", error);
}
return consumedData;
}
and call the function using await
const data = await consumeData();

escape loop using an error from async function?

let me explain what I mean using an example
async function async_function(){
await new Promise(r=>setTimeout(r,3000));
throw 'task completed'
}
async function do_something_meanwhile() {
await new Promise(r => setTimeout(r, 500));
console.log(Math.floor(Math.random()*10));
}
(async ()=>{
try {
async_function(); //this returns an error after a while
while (...)
await do_something_meanwhile();
} catch (err) { console.log('exited with error:',err) }
console.log('moving on');
})();
I'm trying to run an async function and after it is complete immediately terminate the loop,
the best way I could think of (without any time delay) was to send an error
but it gives this error instead of moving on after it's done:
node:internal/process/promises:246
triggerUncaughtException(err, true /* fromPromise */);
^
[UnhandledPromiseRejection: This error originated either by throwing
inside of an async function without a catch block,
or by rejecting a promise which was not handled with
.catch(). The promise rejected with the reason "task
completed".] {
code: 'ERR_UNHANDLED_REJECTION'
}
is there a way around this or a better to achieve the desired effect?
You can handle rejection by setting an error variable that you can check in the loop:
try {
let error;
async_function()
.catch(err => error = err);
while (...) {
if (error) {
throw error;
}
await do_something_meanwhile();
}
} catch (err) {
console.log('exited with error:',err)
}
If you need to proactively tell do_something_meanwhile to terminate as well, you could use an AbortController and pass its signal to do_something_meanwhile.
try {
let error;
const controller = new AbortController();
const { signal } = controller;
async_function()
.catch(err => {
error = err;
controller.abort();
});
while (...) {
if (error) {
throw error;
}
await do_something_meanwhile(signal);
}
} catch (err) {
console.log('exited with error:',err)
}
I think if I were doing that, I might subclass AbortController so I can put the error in it:
class AbortContollerWithError extends AbortController {
abort(error) {
this.error = error;
super.abort();
}
}
then:
try {
const controller = new AbortController();
const { signal } = controller;
async_function()
.catch(err => {
controller.abort(err);
});
while (...) {
if (signal.aborted) {
throw controller.error;
}
await do_something_meanwhile(signal);
}
} catch (err) {
console.log('exited with error:',err)
}
...or something along those lines.
You asked how you'd use the signal in do_something_meanwhile, and suggested in a comment that you're really using a timer in it. That's where the signal's abort event comes in handy, you can use that to settle the promise early:
async function do_something_meanwhile(signal) {
let cancelError = {};
try {
await new Promise((resolve, reject) => {
const timer = setTimeout(resolve, 500);
signal.addEventListener("abort", () => {
clearTimeout(timer);
cancelError = new Error();
reject(cancelError);
});
});
console.log(Math.floor(Math.random() * 10));
} catch (error) {
if (error === cancelError) {
// Probably do nothing
} else {
// Something else went wrong, re-throw
throw error;
}
}
}
Promise.all can run async_function and do_something_meanwhile in parallel mode.
While Promise/A doesn't have a cancel method, you can define a stopFlag, and check it in do_something_meanwhile function and the while loop.
let stopFlag = false
async function async_function() {
await new Promise(r=>setTimeout(r, 3000));
throw 'task completed'
}
async function do_something_meanwhile() {
await new Promise(r => setTimeout(r, 500));
if (!stopFlag) {
console.log(Math.floor(Math.random() * 10));
}
}
(async()=>{
try {
await Promise.all([
async_function().catch((err) => {
stopFlag = true
throw err
}), // this returns an error after a while
(async () => {
while (!stopFlag)
await do_something_meanwhile();
})()
])
} catch (err) {
console.log('exited with error:', err)
}
console.log('moving on');
})();

Use async await function with mongoose query in nodejs

I tried to make async and await function in mongoose. but in one case it simply didn't work while in another case it shows syntax error.
here is my code
exports.updateDiscount= async (_id,discount) =>
{
try
{
console.log(_id,discount);
Discount.findOne({_id},(err,user) =>
{
if(user)
{
user.discountRate=parseFloat(discount);
let saveUser= await user.save();
if(saveUser)
{
console.log("Discount saved");
return true
}
}
})
} catch(err)
{
console.log(err);
}
}
I am using the thing function in another module
if( updateDiscount(item.userid,discount) === true)
{
}
Solution ::
exports.updateDiscount= async (_id,discount) =>
{
try
{
console.log(_id,discount);
let user = await Discount.findOne({_id});
if(!!user)
{
user.discountRate=parseFloat(discount);
let saveUser= await user.save();
if(!!saveUser)
{
console.log("Discount saved");
return true
}
}
} catch(err)
{
console.log(err);
}
}
you need to await the function
const answer = await updateDiscount(item.userid,discount);
if(answer) {
}

Confusion around 'nested' try/catch statements in Javascript

Essentially I have an async function containing a try/catch that calls another async function also containing a try catch, and I'm getting a bit confused about how to properly implement what I'm doing. Some "pseudocode" showing my current implementation:
const main = async () => {
try {
const test = await secondFunc();
console.log(test);
} catch(err) {
console.log('Found an error!');
console.log(err);
}
const secondFunc = async () => {
try {
await performSomeRequestExample();
} catch(err) {
if (err.x === 'x') {
doSomething();
} else {
//********
throw err;
//********
}
}
So what I'm trying to do is get the throw(err) (surrounded by the asterisks) to be caught by the catch in main() which will also call the console.log('Found an error!'), but what currently happens is the error is thrown from secondFunc(), the catch in main() is never hit and I get an unhandled promise rejection.
Any guidance on what I'm doing wrong?
My advice is to minimize using try/catch unless absolutely necessary. With async functions (or any functions that return a Promise object) you can usually simplify things by not worrying about try/catch blocks unless you need to do something specific with certain errors. You can also use .catch rather than try/catch blocks to make things easier to read.
For example your code above could be written like this:
const main = async () => {
const test = await secondFunc().catch(err => {
console.log("Found an error from secondFunc!", err);
throw err; // if you want to send it along to main's caller
});
if (test) {
console.log("Test", test);
}
};
const secondFunc = () => {
return performSomeRequestExample().catch(err => {
if (err.x === "x") {
doSomething();
} else {
throw err;
}
});
};
const performSomeRequestExample = () => Promise.reject("bad");
main().then(
() => console.log("worked"),
err => console.log("failed from main", err)
);
In secondFunc we don't need to use async since we can just return the promise coming back from performSomeRequestExample and handle any failures in the .catch.
You should use
const secondFunc = async () => {
performSomeRequestExample().then(res =>{
console.log(res);
})
.catch(err => {
console.log(err);
}
)
Add a return before the await of performSomeRequestExample.
const secondFunc = async () => {
try {
return await performSomeRequestExample();
} catch (err) {
if (err.x === 'x') {
console.log('x');
} else {
throw err;
}
}
}
or you can also use .catch() after the awaited function.
Another solution can be like this
const main = async() => {
try {
const test = await secondFunc();
console.log(test);
} catch(err) {
console.log('Found an error!');
console.log(err);
}
}
const secondFunc = async () => {
//return await performSomeRequestExample(); //for success
return await performSomeRequestExample(2); //for error
}
const performSomeRequestExample = async(abc=1) => {
return new Promise(function(resolve,reject){
if(abc ==1){
setInterval(resolve("yes"),400);
}else{
setInterval(reject("opps"),400);
}
});
}
main();
Test this code at this link:
https://repl.it/repls/JoyfulSomberTelevision

Receiving undefined when trying to set return value of await function as a constant

I'm trying to set a constant to an await function to get the return information from getInfo. I can console long the object before returning it. But when I try to console log the value in post I get undefined. What am I doing wrong?
router.post('/', function(req,res,next) {
(async function(){
const modifierInfo = await getInfo();
console.log("returns undefined", modifierInfo)
//do more with return info after
})().catch(next)
});
const getInfo = () => {
(async function(){
try {
const ps = new sql.PreparedStatement(pool);
const statement = await ps.prepare("selectQuery");
const result = await statement.execute();
const modifierInfo = await result.recordset[0];
await statement.unprepare();
console.log("returns object", modifierInfo)
return modifierInfo;
} catch (err) {
console.log(err)
}
})()
};
I think the issue is that getInfo itself needs to by async. try something like this:
router.post('/', async (req,res,next) => {
try {
const modifierInfo = await getInfo(req.body.groupID);
console.log(modifierInfo)
} catch(err) {
console.log(err)
}
});
async function getInfo(groupID) {
try {
const ps = new sql.PreparedStatement(pool);
const statement = await ps.prepare("selectQuery");
const result = await statement.execute();
const modifierInfo = await result.recordset[0];
await statement.unprepare();
console.log("returns object", modifierInfo)
return modifierInfo;
} catch (err) {
console.log(err)
}
};

Categories