How do I convert promises to async await - javascript

login() {
return new Promise((resolve, reject) => {
userCollection.findOne({email: this.data.email}).then((myUser)=>{
if (myUser && myUser.password == this.data.password) {
resolve("Congrats! Successfully logged in");
} else{
reject("Login failed");
}
}).catch(()=>{
reject("Please try again later")
})
})
}
This is my model and I can use it to find data from Mongodb. I'm using express js. But, I want to know how I can use async await to do exactly the same thing that the above promise does. I mean, I would like to convert this code to async await way.
Any assistance would be highly appreciated.

This should suffice:
async function login() {
try {
const user = await userCollection.findOne({ email: this.data.email });
if (user && user.password === this.data.password) {
// handle valid user
}
else {
// handle not found user or password mismatch
}
}
catch (error) {
// handle or rethrow error
}
}
Duplicating your case will result in:
async function login() {
try {
const user = await userCollection.findOne({ email: this.data.email });
if (user && user.password === this.data.password) {
return 'Congrats! Successfully logged in';
}
else {
throw new Error('Login failed');
}
}
catch (error) {
throw new Error('Please try again later');
}
}
Then in your caller code you can await(or .then() it, but prefer await) the result of login:
try {
const loginResult = await login();
}
catch(error) {
// handle error
}
Note that in doing so, you will once again need to mark the caller function as async for you to be able to use the await operator.

Related

Using async functions as conditions

Lets say i want to run an if statment where the condition is async function.
const con = require('./con');
if(con.con('email#gmail.com')
console.log('User exists!')
else {
console.log('user does not exist?')
}
This is the function, it uses mongoose findOne which is an async task.
const User = require ('../nodeDB/models/user.js');
const con = function (email) {
User.findOne( { userEmail: email }, function (err, doc) {
if(err) {
console.log(err);
}
if (doc) {
return false;
} else {
return true;
}
});
}
module.exports.con = con;
The problem is that the if statment gets called before the con can get executed which then does'nt set the condition.
You can do it this way :
const con = userEmail => User.findOne({userEmail}).lean().exec();
(async () => {
if (await con('email#gmail.com')) {
console.log('User exists!')
} else {
console.log('user does not exist?')
}
})()
Return User.findOne from your function.
(optional) 2. Add it .lean() (returns simple JSON, faster)
(optional) 3. Add it .exec() so it returns a true Promise and not just a thenable
now you can simply await con() anywhere inside an async function, just as if it was synchronous.
Firstly your con() function doesn't return anything. You will need to return User.findOne(....)
Your if statement needs to respect the fact that the async task has to complete first.
con.con('email#gmail.com')
.then((exists) => {
if (exists)
console.log('User exists!')
else {
console.log('user does not exist?')
}
})
Or with aynsc/await:
async function checkIfUserExists() {
if (await con.con('email#gmail.com')
console.log('User exists!')
else {
console.log('user does not exist?')
}
}
Use await or put your logic in then block.
// must be in async declared function
if (await foo()) {
}
else {
}
// or
foo().then(res=>{
if (res) {
}
else {
}
})

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) {
}

Can't change code from .then to async/await

trying to change .then, like this:
User.prototype.login = () => {
return new Promise((resolve, reject) => {
this.cleanup();
usersCollection
.findOne({ username: this.data.username })
.then((attemptedUser) => {
if (attemptedUser && attemptedUser.password == this.data.password) {
resolve("logged in");
} else {
reject("invalid something");
}
})
.catch(() => {
reject("Please, try again later");
});
});
First one works perfectly, but when I try to change it to async/await, like this:
User.prototype.login = () => {
return new Promise(async (resolve, reject) => {
this.cleanup();
try {
const attemptedUser = await usersCollection.findOne({ username: this.data.username });
if (attemptedUser && attemptedUser.password == this.data.password) {
resolve("logged in");
} else {
reject("invalid something");
}
} catch {
reject("Please, try again later");
}
});
};
it gives me an error that this.cleanup() is not a function, and after a few tries, I realized that async somehow change "this".
can you please help me, where did I made an error?
2 problems in your code:
Functions defined on a prototype object should be regular functions instead of arrow functions because functions defined on objects are used as methods, i.e. value of this inside them refers to instances of the constructor function or class. Using an arrow function will set incorrect value of this and that is most likely the cause of error in your code.
You have mixed promise-chaining with async-await syntax.async functions always return a Promise, so instead of explicitly returning a Promise object, make login function an async function and return the string from the function which is same as calling resolve() function with the string. To reject a promise, throw an error from an async function.
This is how you should define login function
User.prototype.login = async function() {
this.cleanup();
try {
const attemptedUser = await usersCollection.findOne({username: this.data.username});
if (attemptedUser && attemptedUser.password == this.data.password) {
return "logged in";
}
throw new Error("invalid something");
} catch (error) {
console.log("Please, try again later");
throw error;
}
};

Changing script from request to axios - log pending promise

I'd like some help please as I'm quite new in node.js and working with node packages.
I'm having the following script which makes a GET http request running on node using request which is deprecated now
const foo = (bar, callback) => {
const url = 'https://some.api.com?key=abc123';
request({url: url, json: true}, (error, response) => {
if (error) {
callback('Oops, there is an error!', undefined);
} else if(response.body.foobarArray.length === 0) {
callback('No data found', undefined);
} else {
callback(undefined, {
foobar1: response.body.foobar1,
foobar2: response.body.foobar2,
})
}
});
}
console.log(foo('Hello')); // this logs {foobar1: 'Hello', foobar2: 'World'}
I'm trying to rewrite it using axios instead, so this is my code
const foo = async (bar) => {
const url = 'https://some.api.com?key=abc123';
try {
const response = await axios.get(url);
if (response.body.foobarArray.length === 0) {
return 'No data found';
} else {
return {
foobar1: response.body.foobar1,
foobar2: response.body.foobar2,
};
}
} catch (error) {
return 'Ooops! Something went wrong :(';
}
};
console.log(foo('Hello')); // This logs `Promise { <pending> }`
I'm not sure what I'm doing wrong here as I'm not very familiar how promises work exactly, but how can I fix this?
const foo = async (bar) => {
const url = 'https://some.api.com?key=abc123';
try {
return await axios.get(url).then(response => {
return new Promise((resolve, reject) => {
if (response.body.foobarArray.length === 0) {
return reject('No data found');
} else {
return resolve({
foobar1: response.body.foobar1,
foobar2: response.body.foobar2,
});
}
})
}).catch(err => {
return Promise.reject(err);
});
} catch (error) {
// return 'Ooops! Something went wrong :(';
return Promise.reject(`an error occurred : ${error}`);
}
};
foo('hello').then(result => {
console.log(result);
}).catch(err => {
console.log(`error ! : ${err}`);
});
async functions returns a promise. async functions use an implicit Promise to return its result. Even if you don't return a promise explicitly async function makes sure that your code is passed through a promise
as you are using axios asynchronous , it's response is a promise which must be handled inside .then().catch() functions .
if no error occurs you can access the response inside your .then() , else you will have access to your error on .catch()
inside your .then() you can now do what you want with data , returning a new Promise , using resolve() for success and reject() for failure .
You have 2 options here:
Option 1
Any async function returns a Promise (behind the scenes) so:
foo('Hello').then(console.log).error(console.error);
Option 2
You need to await for the result of foo function but, at the moment, you can't use await out of function scope level. So:
async function main() {
try {
const result = await foo('Hello');
console.log(result);
} catch (err) {
console.error(err);
}
}
main();
In future Node.js releases, using await at global scope will be allowed.

Confused between promise and async/awaits

I'm a novice in Node JS. I practice promise and I successfully used it. What I understand is with using a promise you can hold the output and send resolve and reject. I used in database operation.
Then someone suggested me to use async/awaits. So here is my code which ran successfully the first time.
shop.js file
const models = require("../models");
const shopModel = models.Shop;
exports.checkShop = function(shopName) {
return new Promise((reslove, reject) => {
shopModel
.findOne({ where: { shop: shopName } })
.then(rs => {
if (rs) {
reslove(rs);
}
})
.catch(err => {
reject(err.toString());
});
});
};
And the file where i called this
const shopController = require("./shop");
exports.getInstall = function(req, res) {
const shop = req.body.shop;
if (!cn(shop)) {
shopController
.checkShop(shop)
.then(
shopCheck =>
function() {
if (shopCheck) {
res.send(`Welcome back ${shopCheck.shop}`);
} else {
//my else stuff
}
}
)
.catch(
e =>
function() {
res.state(500).send(e);
}
);
} else {
return res
.status(400)
.send(
"Missing shop parameter. Please add ?shop=your-development-shop.myshopify.com to your request"
);
}
};
And this is how I tried to replace it with async/awaits. But it does not work.
exports.checkShop = async function(shopName) {
try{
var rs = await shopModel.findOne({ where: { shop: shopName } });
if(rs){
return rs;
}
else{
return false;
}
}
catch(e){
return Promise.reject(new Error(400));
}
};
And the other file
exports.getInstall = function(req, res) {
const shop = req.body.shop;
if (!cn(shop)) {
var shopCheck = shopController.checkShop(shop);
try {
if (shopCheck) {
res.send(`Welcome back ${shopCheck.shop}`);
} else {
// else stuff
}
} catch (e) {
res.state(500).send(e);
}
} else {
return res
.status(400)
.send(
"Missing shop parameter. Please add ?shop=your-development-shop.myshopify.com to your request"
);
}
};
Every function with the async keyword before it will (explicitly or implicitly) return a promise.
So when you call shopController.checkShop you will either have to do something like
shopController.checkShop().then(.... )
or make getInstall an async function as well so that you can use await inside it.
exports.getInstall = async function(req, res) {
// other code here..
const result = await shopController.checkShop(shop);
//..
}
Edit:
If you want to make getInstall async and use await on checkShop you will have to catch the potential rejection using try {} catch like you did in checkShop.

Categories