1

I am on Node-Mongo Environment. I am converting the String password to bcrypt. After this save it to the DB. But there is a problem that Bcrypt and after that functions not run in a sequential manner. For that, I used SetTimeout() function to run other function little late.

But as far as I know That this one is not a good Practice. Suppose if Anyhow Bcrypt Takes time and after that timer function call the otherone so may be collision Occur.

My Code is Like this:

var globalpasswordholder;
bcrypt.genSalt(10, function(err, salt) {
                bcrypt.hash(req.body.password, salt, function(err, hash) {
                    req.body.password = hash;
                    globalpasswordholder = req.body.password;
                });
            });
            setTimeout(function(){
                user.password = globalpasswordholder;
                user.resetPasswordToken = undefined;
                user.resetPasswordExpires = undefined;

                user.save(function(err) {
                    req.logIn(user, function(err) {
                        done(err, user);
                    });
                });
            },1000);

If I not use setTimeout function then on console my globalpasswordholder is undefined.

Anyone have a solution for this. Thanks in advance.

Ankit
  • 951
  • 1
  • 9
  • 29
  • Possible duplicate of [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) – Liam Feb 14 '18 at 08:50
  • `bcrypt.hash` returns promise, so you need a `then`. It's all in [the docs, (see with then)](https://www.npmjs.com/package/bcrypt) – Liam Feb 14 '18 at 08:52

2 Answers2

1

As javascript is single threaded, so your genSalt() will be pushed into event loop and it won't wait for a response and jump to next statement. and after your gensalt() will finish it's execution it's callback function(err, hash) {...}); will be executed. Write your code in the callback of a genSalt() method like this:

bcrypt.genSalt(10, function (err, salt) {
    bcrypt.hash(req.body.password, salt, function (err, hash) {
        req.body.password = hash;
        globalpasswordholder = req.body.password;

        user.password = globalpasswordholder;
        user.resetPasswordToken = undefined;
        user.resetPasswordExpires = undefined;

        user.save(function (err) {
            req.logIn(user, function (err) {
                done(err, user);
            });
        });
    });
});

And bcrypt.genSalt also provides promisified method so you can also use it like this:

var globalpasswordholder;
bcrypt.genSalt(10)
        .then(salt => {
            return bcrypt.hash(req.body.password, salt);
        })
        .then(hash => {
            req.body.password = hash;
            globalpasswordholder = req.body.password;

            user.password = globalpasswordholder;
            user.resetPasswordToken = undefined;
            user.resetPasswordExpires = undefined;

            return user.save();
        })
        .then(() => {
            req.logIn(user, function (err) {
                done(err, user);
            });
        })
        .catch(e => console.log(e));

This is a good video to understand the concepts.

Ridham Tarpara
  • 5,970
  • 4
  • 19
  • 39
  • Thank you So much @Ridham Tarpara. And thanks for sharing the Video tutorial too.... – Ankit Feb 14 '18 at 09:05
  • In your second example, If you returned the result of `bcrypt.hash` and `user.save` you could just chain the promises (`then`) which would result in much cleaner code. – Liam Feb 14 '18 at 09:31
  • 1
    I was actually thinking more like this https://jsfiddle.net/r1n4gLz5/1/. It's a minor point. – Liam Feb 14 '18 at 13:33
1

Just put the user related code inside the callback function for bcrypt.

var globalpasswordholder;
bcrypt.genSalt(10, function(err, salt) {
    bcrypt.hash(req.body.password, salt, function(err, hash) {
        req.body.password = hash;
        globalpasswordholder = req.body.password;

        user.password = globalpasswordholder;
        user.resetPasswordToken = undefined;
        user.resetPasswordExpires = undefined;

        user.save(function(err) {
            req.logIn(user, function(err) {
                done(err, user);
            });
        });
    });
});
Wesgur
  • 3,140
  • 3
  • 18
  • 28