Search code examples
javascriptpromiseasync-awaites6-promisebcrypt

Proper usage of promise await and async function


router.post("/register", function (req, res) {

    console.log(req.body);

    // generate a salt
    (async function(){


    const salt = await bcrypt.genSalt(10);

    // hash the password along with our new salt
    const hash = await bcrypt.hash(req.body.txtPassword1, salt);
    return hash;
    })().then((data)=>{
        var txtPassword = data;
        let newUser = new userModel({
            userName: req.body.txtUserName,
            email: req.body.txtEmail,
            profilePic: req.body.txtFileUpload,
            password: txtPassword,
            isAdmin: false

        });
        newUser.save((function (err) {
            if (err) {
                console.log("failed to save the new User ! : ", err);

            } else {
                console.log("New user has been added successfully with Id", newUser._id);
            }
        }))

        req.flash('success', 'Registeration Successful');

        console.log("Session value ", req.session);
        console.log("value of txt password => ", txtPassword)
        res.render("blogHome", { title: "Blogs || Home" });
    });


}); 

I want to know if this is the proper way to use await. I had to resort to this way because when I simply tried using

var hash = await bcrypt.hash(req.body.txtPassword1,salt);

I was getting unexpected identifier error when I went with above code and when I googled I found out that await have to be used inside a async function so I wrapped the whole thing in side a IIFE and used normal promise handling with .then() But I feel unknowingly I have complicated a simple thing . Can anyone point out the simplest way to do this. The reason I was forced to use promise was because due to asynchronous execution database save statement always executed before the hash was calculated and it would mean password is empty which in turn triggers schema validation for password field


Solution

  • That's correct other than that you're not handling errors, which you need to do — otherwise, for now, you get an "unhandled rejection" error in the console, and as of some upcoming Node.js version, it'll terminate the process on unhandled rejections.

    But I feel unknowingly I have complicated a simple thing .

    :-) That's because you're dealing with some promise-based things and some older-style Node-callback based things. But you can make it cleaner by promisifying the old-style callback things.

    Suppose you updated newUserModel.save so it returned a promise instead of having a Node-style callback. Then:

    router.post("/register", function (req, res) {
        // generate a salt
        (async function(){
            const salt = await bcrypt.genSalt(10);
    
            // hash the password along with our new salt
            const txtPassword = await bcrypt.hash(req.body.txtPassword1, salt);
            let newUser = new userModel({
                userName: req.body.txtUserName,
                email: req.body.txtEmail,
                profilePic: req.body.txtFileUpload,
                password: txtPassword,
                isAdmin: false
    
            });
            await newUser.save(); // *** Assumes a new promise-enabled `save`
            console.log("New user has been added successfully with Id", newUser._id);
    
            req.flash('success', 'Registeration Successful');
    
            console.log("Session value ", req.session);
            console.log("value of txt password => ", txtPassword)
            res.render("blogHome", { title: "Blogs || Home" });
        })().catch(err => {
            // handle error
        });
    });
    

    If this is Express, you might also look Koa (from the same people), which lets you make the entire post callback async and correctly handle errors at the same time (with middleware).