I'm beginner in nodejs, This function returns "Promise {pending}
" I Appreciate any help.
Thanks
async function getCurrentUser(id){
try{
let user = User.findOne({id:id})
return user;
}catch(err){
return err;
}
}
You missing the await in front of some function that return a Promise
let user = await User.findOne({id:id})
Promise is an immutable async operation that need time to finish so you either use async/await like you did or chain the promise with .then call like
User.findOne({ id })
.then((response) => {
// do sth with the resposne
});
recommend you to read Async & Performance from YDKJS series
full rewrite of code:
async function getCurrentUser(id) {
try {
let user = await User.findOne({ id: id })
return user;
} catch (err) {
return err;
}
}
// getCurrentUser usage
async function doSth(){
let user = await getCurrentUser();
}
usage clarification:
putting async in front of a function make this function return type a promise no matter what you return inside it so the only two way to use such a function is just like how you use a promise either use it in another async function using await or use .then() chaining function
u missing await
async function getCurrentUser(id){
try{
let user = await User.findOne({id:id})
return user;
}catch(err){
return err;
}
Related
I would like to use await method inside the async.Series
Here is my node js code
const async = require("async");
async.eachSeries(myArr, function (arr, callback) {
let test = await db.collection('coll').findOne({ _id: arr }); //I couldn't use await here
callback(null, test);
}, function (err) {
console.log("Done");
});
I have tried
async.eachSeries(myArr, async function (arr, callback) {
let test = await db.collection('coll').findOne({ _id: arr }); //It not working here
callback(null, test);
}, function (err) {
console.log("Done");
});
And
async.eachSeries(myArr, async.asyncify(async(function (arr, callback) {
let test = await db.collection('coll').findOne({ _id: arr }); //It not working here
callback(null, test);
})), function (err) {
console.log("Done");
});
Correct me If the approach is wrong or let me know how to achieve await inside the async each.
As async document said:
Using ES2017 async functions Async accepts async functions wherever we
accept a Node-style callback function. However, we do not pass them a
callback, and instead use the return value and handle any promise
rejections or errors thrown.
If you still pass the callback function as the second parameter of eachSeries 's callback function, it will not work as expected. Just remove
callback and return the result:
async.eachSeries(myArr, async (arr) => { // remove callback parameter
const test = await db.collection('coll').findOne({ _id: arr }); // wait the response
// ...
return test; // return response
}, function (err) {
console.log("Done");
});
Or just use for...loop instead of eachSeries:
// inside a async function
for (const i of myArr) {
const test = await db.collection('coll').findOne({ _id: arr });
// Do something with `test`
}
console.log("Done");
Why mix callbacks with promises?
Right aproach will be use an async iterator Symbol.
If not first attempt would be valid
eachSeries(array, async function(arr, cb) {
await ....
});
I'm reading data from db with using await so I used Promise but the function seems to return nothing
async function read() {
return new Promise((resolve, reject) => {
const db = new DB();
db
.read()
.then(result => {
resolve(result);
}).catch(() => {
reject('db-error');
});
});
}
(async () => {
const data = await read();
console.log(data); // undefined
})();
How can I make read() return result?
You are making it more complicated than it has to be. If you are already using an API that returns a promise then there is no need to use the promise constructor yourself.
And declaring a function as async is only necessary if you are using await in it to deal with promises.
So either do:
function read() {
const db = new DB();
return db
.read()
.catch(() => {
return 'db-error';
});
}
Or
async function read() {
const db = new DB();
try {
return await db.read();
} catch(error) {
return 'db-error';
}
}
If you are still not getting the value you want then you are not using the database API correctly and you have to read its documentation to figure out how to get back the right data.
The awesome guys who write the MDN Web Docs say that the result of await will be undefined if the promise that is being waited on is rejected: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#handling_rejected_promises
Check out the following scenario.
This is a simple function that returns a Promise:
function asyncFunc(waitTime) {
return new Promise((resolve, reject) => {
setTimeout(() => {
// say we prefer people who do things in 3 seconds or less
if (waitTime <= 3000) {
resolve('Promise resolved! You\'re fast! :)');
} else {
reject('Promise rejected! You\'re slow! :(');
}
}, waitTime);
});
}
Let's test the function using a method similar to yours:
async function testAsyncFunc(waitTime) {
try {
const result = await asyncFunc(waitTime);
console.log(result);
} catch(error) {
console.error(error.message);
}
}
testAsyncFunc(3000); // Returns `Promise resolved! You're fast! :)`, as expected
testAsyncFunc(3001); // Returns `undefined` instead of `Promise rejected! You're slow! :(`
But since we want the actual rejection error of the asynchronous operation instead of undefined, the solution is to chain catch to the await statement to catch any rejection errors immediately you call the asynchronous function and then throw the error so it can be caught by any catch error handler you may want to use, like so:
async function testAsyncFunc(waitTime) {
try {
const result = await asyncFunc(waitTime)
.catch(error => {
// throw the rejection error so it can be handled by the catch block below
throw new Error(error);
});
// if no errors
console.log(result);
} catch(error) {
console.error(error.message);
}
}
testAsyncFunc(3001); // Returns the expected result: `Promise rejected! You're slow! :(`
I was trying to use async/await functionalities and my problem is that I have an async function which I need to return some data from and inside it I nested 3 await functions where the last one returns the value for the whole function, but I could not do that because the last await is on find query from mongodb and it returns the found element only. So I wanted to know if there is some way to to that data from that await function.
async register_Employee_Credential (id,req,res){
try{
let employee_credential= new Employee_credential({
employee: id,
username: req.body.username,
password: req.body.password
});
await bcrypt.genSalt(10,async (err,salt)=>{ //first await function
await bcrypt.hash(employee_credential.password,salt, async (err,hash)=>{ //second await function
if(err) console.log("error while generating salt");
employee_credential.password = hash;
result = await Employee_credential.create(employee_credential,async (err,result)=>{ // third await function
if(err)
{
var errMessage = await help.Property_Validator(err);
return errMessage; // this is the return message i need
}
})
})
})
return errMessage; //this is the final return for the calling function
}catch(err){
console.log("employee creditial error furthur: " + err);
}
}
An async function ALWAYS returns a promise. That is built into the language and you cannot change it. So, you can never return a plain value from an async function.
Further a plain asynchronous callback in your function gets called long AFTER the function has already returned that promise so you cannot return a value from the function from within that callback.
Further yet, await only does anything useful when you are awaiting a promise so your await in this await Employee_credential.create() does nothing useful. The same with each of your other await statements. They are not awaiting promises so they do nothing useful. Please read about how await actually works and is used rather than just sticking it places hoping it solves some problem. It only works properly when used in a very specific way. You need to learn that.
And, finally, you can NEVER return an asynchronously retrieved value directly from a function. Javascript just doesn't work that way. You will have to communicate back the return value via a callback, a promise or an event.
You will need to either promisify all asynchronous functions within your async parent function so that you can use await with them or you will need to stop using async/await and communicate back the return result via a callback.
Since none of your three asynchronous operations in your function directly support promises, then the least amount of change to your code woudl be to add a callback argument to your function and go the traditional callback method of communicating back asynchronous results. You then pass the callback into the function and get the result inside that callback when it is called.
register_Employee_Credential(id, req, res, callback) {
try {
let employee_credential = new Employee_credential({
employee: id,
username: req.body.username,
password: req.body.password
});
bcrypt.genSalt(10, async (err, salt) => {
if (err) {
console.log(err);
return callback(err);
}
bcrypt.hash(employee_credential.password, salt, async (err, hash) => {
if (err) {
console.log(err);
return callback(err);
}
employee_credential.password = hash;
Employee_credential.create(employee_credential, async (err, result) => {
if (err) {
var errMessage = help.Property_Validator(err);
callback(errMessage);
} else {
callback(null, result);
}
})
})
})
} catch (err) {
console.log("employee creditial error furthur: " + err);
callback(err);
}
}
If you want to use promises, then bcrypt appears to already have a promise interface built in if you do NOT pass it a callback so you just have to promisify the .create() method and can do that like this:
const {promisify} = require('util');
async register_Employee_Credential(id, req, res) {
let employee_credential = new Employee_credential({
employee: id,
username: req.body.username,
password: req.body.password
});
// promisify the create method
Employee_credential.createP = promisify(Employee_credential.create);
let salt = await bcrypt.genSalt(10);
let hash = await bcrypt.hash(employee_credential.password, salt);
employee_credential.password = hash;
try {
let result = await Employee_credential.createP(employee_credential);
return result;
} catch(err) {
let errMessage = help.Property_Validator(err);
throw errMessage;
}
}
You would use the async/promise version by calling:
register_Employee_Credential(id, req, res).then(result => {
console.log(result);
}).catch(err => {
console.log(err);
});
I want to use the async function to bring out a particular value from my database to my the function global so I can use it in other parts of my application.
async function dimension() {
const result = await Settings.find({_id : "5d7f77d620cf10054ded50bb"},{dimension:1}, (err, res) => {
if(err) throw new Error(err.message, null);
const holder = res[0].dimension;
return holder;
console.log(holder) /// this print the expected result, that i want to make global
});
return {
result
};
};
console.log(dimension())
but the console.log of the dimension() gives me this
Promise { <pending> }
instead of the same value that
console.log(holder)
gives me nothing.
The problem is you are printing the result of dimension() as soon as you call it, but since this function is async, it returns a promise that is not yet resolved.
You do not need to use async/await here. Settings.find() seems to return a Promise. You can just return directly this Promise and use .then() to do something once that promise is resolved.
Like this :
function dimension () {
return Settings.find({ _id: '5d7f77d620cf10054ded50bb' }, { dimension: 1 }, (err, res) => {
if (err) {
throw new Error(err.message, null);
}
return res[0].dimension;
});
}
dimension().then(result => {
//print the result of dimension()
console.log(result);
//if result is a number and you want to add it to other numbers
var newResult = result + 25 + 45
// the variable "newResult" is now equal to your result + 45 + 25
});
More info on Promises and async/await
You have to await for your result, like this:
const result = await dimension();
console.log(result);
In that case, you don't even to make the original function async, just write it like this:
function dimension() {
return Settings.find({_id : "5d7f77d620cf10054ded50bb"},{dimension:1}, (err, res) => {
if(err) throw new Error(err.message, null);
const holder = res[0].dimension;
return holder;
});
};
async function myGlobalFunc() {
const result = await dimension();
console.log(result);
}
The best way to have this globally available is to just put your function dimension in a file somewhere. Then where you need the value, you just require it and await its value. E.g.
// get-dimension.js
// ...const Settings = require... comes here
module.exports = function getDimension() {
return Settings.find({_id : "5d7f77d620cf10054ded50bb"},{dimension:1}, (err, res) => {
if(err) throw new Error(err.message, null);
const holder = res[0].dimension;
return holder;
});
}
// your other modules, e.g.
// my-service-handler.js
const getDimesion = require('./get-dimension');
async function myServiceHandler() {
const dimension = await getDimension();
// do stuff with dimension.
}
You're using async/await, but you're mixing it with callbacks, this is not desirable as it leads to confusion. It's not clear what you expect to happen in the callback, but return holder; likely doesn't do what you expect it to do, returning from a callback does not work the same way returning from a promise handler works. Your entire implementation should work with promises so that the async/await syntax reads more naturally (as it was intended).
async function dimension() {
// We're already awaiting the result, no need for a callback...
// If an error is thrown from Settings.find it is propagated to the caller,
// no need to catch and rethrow the error...
const res = await Settings.find({_id: "5d7f77d620cf10054ded50bb"}, {dimension: 1});
return {result: res[0].dimension};
}
(async () => {
try {
console.log(await dimension());
} catch (err) {
console.error(err);
}
})();
Use dimension().then() in your code then it will work fine.
async function globalDimension() {
const data = await Users.findOne({ phone: 8109522305 }).exec();
return data.name;
}
globalDimension().then(data => {
console.log(data);
});
I'm using the Google Maps Geocode API and attempting to use async await. I've defined several functions for handling the request:
function googleGeoCode(address) {
const googleMapsClient = require('#google/maps').createClient({
key: 'googleMapsApiKeyGoesHere',
Promise: Promise
});
return googleMapsClient.geocode({ address: address }).asPromise();
}
async function getGeoCode(address, errors, res) {
try {
const result = await googleGeoCode(address);
return result;
} catch (error) {
errors.googleMapsClient = error;
return res.status(400).json(errors);
}
}
I then use the getGeoCode function in my express route:
const geoResponse = getGeoCode(req.body.address, errors, res);
The await portion of the function is not working correctly. If i console log geoResponse I get Promise { <pending> }
I'm new to using async await and I'm not sure if I am doing something incorrect here. Any help is really appreciated!
An async function always returns a promise or wraps the return value into promise,you have to resolve the promise like this
const geoResponse = getGeoCode(req.body.address, errors, res);
geoResponse.then((result)=>{
console.log(result)
}).catch((err)=>{
console.log(err);
})