-1

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);
        }
    }
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • 1
    Does this answer your question? [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – VLAZ Mar 19 '20 at 08:09

1 Answers1

0

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);
});
jfriend00
  • 683,504
  • 96
  • 985
  • 979