最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Async function in mongoose pre save hook not working - Stack Overflow

programmeradmin0浏览0评论

Calling an async function in a pre save hook is returning me undefined for the password. Am I fundamentally misunderstanding async here? I've used it successfully in other areas of my app an it seems to be working fine...

userSchema.pre('save', function (next) {

  let user = this

  const saltRounds = 10;

  const password = hashPassword(user)
  user.password = password;

  next();

})


async hashPassword(user) {

    let newHash = await bcrypt.hash(password, saltRounds, function(err, hash) {

    if (err) {
      console.log(err)
    }

    return hash    

  });

  return newHash

}

Calling an async function in a pre save hook is returning me undefined for the password. Am I fundamentally misunderstanding async here? I've used it successfully in other areas of my app an it seems to be working fine...

userSchema.pre('save', function (next) {

  let user = this

  const saltRounds = 10;

  const password = hashPassword(user)
  user.password = password;

  next();

})


async hashPassword(user) {

    let newHash = await bcrypt.hash(password, saltRounds, function(err, hash) {

    if (err) {
      console.log(err)
    }

    return hash    

  });

  return newHash

}
Share Improve this question asked Feb 15, 2018 at 3:17 ModermoModermo 1,9922 gold badges31 silver badges48 bronze badges 6
  • 1 do you understand that const password = hashPassword(user) will be a Promise - because that's what async functions return (immediately) - therefore, you'd be setting user.password = a_promise and calling next before the promise has resolved - what the next issue will be, does pre save hook understand promises – Jaromanda X Commented Feb 15, 2018 at 3:28
  • In which case, I'd need to use a password.then(user.password = password) ? Which makes sense, but I think I need to better my understanding of async/promises – Modermo Commented Feb 15, 2018 at 3:35
  • 2 indeed, and call next inside .then ... you could avoid .then by making userSchema.pre('save', async function (next) { - then you can const password = await hashPassword(user) - functionally, this is (almost0 identical to the .then pattern – Jaromanda X Commented Feb 15, 2018 at 3:36
  • Got it. Makes sense now. – Modermo Commented Feb 15, 2018 at 3:37
  • of course, other errors in your code include: 1 - async hashPassword(user) { - but user is never used in that function. 2 - where does that function get saltRounds from? 3 - the callback to .hash will return hash regardless if there's an error or not – Jaromanda X Commented Feb 15, 2018 at 3:38
 |  Show 1 more ment

3 Answers 3

Reset to default 4

I think you'd need to handle the promise returned by hashPassword:

 hashPassword(user)
 .then(password => {user.password = password
                    next()}
 )

I don't think you can turn userSchema.pre into an async function.

Mongoose hooks allow async functions in them. It worked for me. Note that the "next" callback parameter is not needed in async functions as the function executes synchronously.

Here is what a correct async/await version of the code posted in the question would be. Please note that the corrections are marked in bold:

userSchema.pre('save', async function () {
  
  let user = this;

  const saltRounds = 10;

  const hashed_password = await hashPassword(user.password, saltRounds);

  user.password = hashed_password;

}); // pre save hook ends here

async hashPassword(password, saltRounds) {

  try {

    let newHash = await bcrypt.hash(password, saltRounds);

  } catch(err){

    // error handling here

  }

  return newHash;

}

Just to clean things up a bit:

userSchema.pre('save', function(next) {
    if (!this.isModified('password')) {
        return next();
    }

    this.hashPassword(this.password)
        .then((password) => {
            this.password = password;
            next();
        });
});

userSchema.methods = {
    hashPassword(password) {
        return bcrypt.hash(password, 10);
    },
}
  • let user = this can be dropped when using an arrow function in then.
  • When using bcrypt.hash() with no callback, it returns a promise.
  • async for hashPassword is redundant when using .then when calling
发布评论

评论列表(0)

  1. 暂无评论