How to use async await in nodejs - javascript

I made an api like below.
I think it works asyncrously well without doubt.
exports.query = async(req, res) => {
try{
const result = await user.findOne({})
res.send(result);
} catch(error) {
res.send(error)
}
}
But when I try this like below, I am not sure it works asyncrously or not.
exports.query = async(req, res) => {
try{
user.findOne({})
.then(async(result) =>{
order.findOne({id: result.id})
.catch(e => res.send(e)
} catch(error) {
res.send(error)
}
}
I have to attach 'await' in front of user.findOne({}) like below?
exports.query = async(req, res) => {
try{
await user.findOne({})
.then(async(result) =>{
Or it doesn't matter? That is, it works same asycrously, even though I don't write await in front to user.findOne using 'then'?
thank you so much for reading.

Generally, inside a single block, you should either use await, or use .then, but not both - similarly, using Promise.prototype.catch is really weird in combination with try/catch where you can already await.
For your exports.query to resolve once the second findOne finishes, await or return both Promises, and connect the inner findOne connected to the outer Promise chain. Consider something like this instead:
exports.query = async (req, res) => {
try {
const userResult = await user.findOne({});
const orderResult = await userResult.findOne({ id: userResult.id });
// do something with orderResult
} catch (error) {
res.send(error)
}
}
If you use .then and catch without await, then it would look like:
exports.query = (req, res) => {
return user.findOne({})
.then((result) => {
return order.findOne({
id: result.id
})
.then((orderResult) => {
// do something with orderResult
})
.catch(e => res.send(e))
});
}
With the code in the second snippet in your question, your try/catch block will never do anything useful, because any problem will trigger the .catch method, and because the Promise isn't being awaited. Better not to mix the two styles - either pick await and try/catchor .then and .catch, but not both, else the control flow may become difficult to make sense of.

First of all, async-await can be used in functions which returns a promise.
Why we have to use await instead of then. await process the code asynchronously by making the execution feel like synchronous.
In your first example, everything works fine as expected. But in the second one, you need to await the findOne query. Here the fineOne will work asynchronously
exports.query = async(req, res) => {
try{
user.findOne({})
.then(async(result) =>{
let orderResult = await order.findOne({id: result.id})
.catch(e => res.send(e)
} catch(error) {
res.send(error)
}
}
which can be again simplified to
exports.query = async(req, res) => {
try{
let result = await user.findOne({});
let orderResult = order.findOne({id: result.id});
} catch(error) {
res.send(error)
}
}

Related

Using async await on .then function with parameters

I'm doing some functional testing with mocha. I stored my functions name, parameters and sucess message in local JSON file. I am checking my database response with local JSON response.
I'm using .then and .catch everywhere. I am looking to clean up a code with async await. How I can use async await here?
it('Check Authentication', (done) => {
readFileData('checkAuth').then(({ params, message}) => {
login.checkAuth({ ...params })
.then((result) => {
assert(result.message === message);
done();
})
.catch((err) => done(err));
});
});
Something like this. Haven't tested it tho. Basically instead of .then() you just await the call. Note that there is async before (done) callback. .catch() can be caught with try/catch block.
it('Check Authentication', async (done) => {
let response = await readFileData('checkAuth');
try {
let message = await login.checkAuth({ ...response.params }); // or w/e the response is
// assert the message
} catch (e) {
// do something with the error
}
});
Changed callback function to async to use `await
Wrapped all await calls in try-catch block to handle errors
Used const for params, message and result variables but if you are going to reassign values later in the code you can use let instead.
done() will be async call. Add await in front of that if you need that too to be sync call
it('Check Authentication', async (done) => {
try {
const { params, message } = await readFileData('checkAuth');
const result = await login.checkAuth({ ...params });
assert(result.message === message);
done();
} catch (err) {
done(err);
}
});

Lambda function not running other async function even with await added to it

I have a Lambda function that isn't running an async function that I am using await on. I am guessing something else is async and I need to await it though I am unsure what can/should be await'ed as documentation for the redis package doesn't talk about promises or async that I saw. I tried putting await in front of the clienthmset... but VS Code says I can't await that. What are my options for getting this to run properly?
Here is the minimum reproducable code I have come up with, note the only things not included in this example are my logger, my imports and my client setup (has password and hostname)
const loadRedis = async (message) => {
client.hmset(`${message.region}:${message._id}`, message, (err, res) => {
if(err) {
logger.error(`Error: ${JSON.stringify(err)}`)
reject(err)
}
if(res) {
logger.info(`Response: ${JSON.stringify(res)}`)
resolve(res)
}
})
}
module.exports.loader = async (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
let input = JSON.parse(event.Records[0].body);
let message = input.Message
const result = await loadRedis(message)
logger.info(message)
logger.info(result)
let output = result
callback(null, output);
};
The logs in CloudWatch Logs shows that the message log is coming find but the result one is coming back with nothing at all other than the log level.
loadRedis is declared async, but you don't return anything, so it's not really await-ing anything..
Probably you just need to do:
const loadRedis = async (message) => {
return new Promise((resolve, reject) => {
return client.hmset(`${message.region}:${message._id}`, message, (err, res) => {
if(err) {
logger.error(`Error: ${JSON.stringify(err)}`)
reject(err)
}
if(res) {
logger.info(`Response: ${JSON.stringify(res)}`)
resolve(res)
}
})
}
}

Improve callback code into async await mongoose

I want improve my old callbacks code in mongose with async/await methods (which are much better to read and organized)
PUT is the problem
I a have a findById, which are correctly
The problem is when try to update document with await user.save(userWithNewProps)
// put
app.put('/:id', async (req, res) => {
try {
const user = await User.findById(req.params.id).exec()
if (user === null) return res.status(404).json(null)
const userWithNewProps = {name: 'Homer', lastame: 'Simpson'}
const userUpdated = await user.save(userWithNewProps) // Doesn't works!
res.status(200).json(userUpdated)
} catch (e) {
return res.status(500).json(e)
}
})
I tried to study many tutorials, and other questions, but is some difficult for me.
Can you check my error?
callback hell
This is the original callback code, works fine, but is the callback hell and demonic spirits:
// put
app.put(
'/:id',
(req, res) => {
User.findById(req.params.id, (err, userFound) => {
if (err) {
return res.status(500).json(err);
}
if (!userFound) {
return res.status(404).json(err);
}
userFound.name = 'Homer';
userFound.lastname = 'Simpson';
userFound.save((err, userUpdated) => {
if (err) {
return res.status(500).json(err);
}
res.status(200).json(userUpdated);
});
});
});
Many thanks
As I understand from our discussion in comments, the problem is in the updating and not when saving data, so you need to inform Mongoose's change tracking of the change.
Informing Mongoose about the changes can be handled by using the markModified() method and it should be before saving.
user.name = 'Homer';
user.lastname = 'Simpson';
user.markModified('name');
user.markModified('lastname');
await user.save();
Regards :)

getting value from a chained promises

im really new to this of promises and im getting headaches trying to understand this, so now im trying to get an answer from a method that returns a promise, then i catch the value in a conditional and make some other operations
let addService = async(req, res) => {
checkCategoryExists(param).then(result => {
if(result){
// code here
}
}).catch(err => console.log(err));
}
let checkCategoryExists = async(param) => {
let docs = db.collection(collectionName).doc(param);
docs.get()
.then(categoryDoc => {
if(categoryDoc.exists){
if(categoryDoc.data().param== param){
return true;
}
} else {
return false;
}
})
.catch(err => false);
}
the method "checkCategoryExists" is a query to a firestore db. When i tried to check if result variable is true or false, it happens to be undefined. its not with ".then()" that i get to catch the value from the returned promise? if someone can help me, thanks in advance
So as mentioned above I think your issue is based on not returning the results of your document search so both examples below handle that.
I also noticed that you were using async tags on your functions but not ever using await so I wanted to give examples of both ways of doing it in case you wanted to use Async/Await but weren't certain how.
In the promise chain example I'm relying on the syntax of arrow functions to create the returns (no {} means return right side of equation) since none of your given code requires data manipulation before return (if your actual code needs that you should of course use brackets and remember your return statement :D )
If you choose to use Async/Await you can structure the code much more closely to synchronous examples and use try catch statements. Sometimes I find this syntax more clear if I have to do a lot of processing/manipulation before returning a result.
Good Luck :)!
// Promise Chains
const addService = (req, res) =>
checkCategoryExists(param)
.then(result => /* do stuff */)
.catch(err => console.error(err.message));
const checkCategoryExists = param =>
db.collection(collectionName.doc(param)
.get()
.then(categoryDoc =>
Promise.resolve((categoryDoc.exists && categoryDoc.data().param === param))
);
// OR using Async/Await
const addService async (req, res) => {
try {
const catExists = await checkCategoryExists(param);
if (!catExists) {
throw new Error('error code');
}
// Do Stuff.
} catch (error) {
console.error(error);
}
};
const checkCategoryExists = async param => {
try {
const docs = await db.collection(collectionName)
.doc(param)
.get();
return (docs.exists && docs.data().param === param);
} catch (error) {
console.error(error)
}
}

Rewrite Code Form Callback to Async Await

I have been trying to convert my existing Express JS code from function callback to Async Await.
The function callback code is
app.get('/contactlist', (req, res) => {
db.contactlist.find((err, docs) => {
res.json(docs);
});
});
And the Async Await code is
app.get('/contactlist', async (req, res) => {
db.contactlist.find(async(err, docs) => {
res.json(await docs);
});
});
The new code works good and I have strong feeling that, it is not the right Implementation of Async Await
You're still using callbacks. You can only switch to async/await, if the API returns promises. app.get() does not return promises, so the following doesn't work with Express:
let (req, res) = await app.get('/contactlist');
try {
let docs = await db.contactlist.find();
res.json(docs);
} catch (err) {
// Handle the error
}
All of that would have to be inside an async function.
What is db in your example? If db.contactlist.find returns a promise, you can use async/await like this:
app.get('/contactlist', async (req, res) => {
try {
let docs = await db.contactlist.find();
res.json(docs);
} catch (err) {
// Handle the error
}
});
you did not convert the callback to async await at all,callback is still there.The right implementation would look like this
app.get('/contactlist', async (req, res) => {
const docs = await getContactList();
res.json(docs)
});
function getContactList() {
let promise = new promise(function(resolve, reject) {
db.contactlist.find({}, function(err, results) {
if (err)
reject(err)
else
resolve(results)
});
});
return promise
}
^EDITS: Here's the complete example, if you have a custom function against await, you can promisify that function by creating and returning a promise in that function

Categories

Resources