Здесь есть два основных вопроса.Поскольку кажется, что вы хотите продолжить делать newLocalStrategy
принимать обратный вызов done
, я предполагаю, что вы не хотите, чтобы он возвращал обещание, а просто используете обещания внутри.
exports.newLocalStrategy = new localStrategy(
(username, password, done) => {
User.find({
username: username
})
.then(user => {
if (user.length == 0) {
return done(null, false, { message: 'unknown user' })
}
})
.catch(err => {
return done(null, err)
})
// this is in the wrong scope, `user` is not defined here
comparePassword(password, user[0].password)
.then(isMatch => {
if (isMatch) return (done, null);
})
.catch(err => {
return done(null, err)
})
});
const comparePassword = (candidatePassword, hash, callback) => {
return new Promise((resolve, reject) => {
bcrypt.compare(candidatePassword, hash, (err, isMatch) => {
if (err) return reject(err);
// resolve takes only one parameter
resolve(null, isMatch);
});
})
}
После внесения исправлений это должно выглядеть следующим образом:
exports.newLocalStrategy = new localStrategy((username, password, done) => {
User.find({ username }).then(users => {
if (users.length === 0) {
throw new Error('unknown user');
} else {
return Promise.all([users, comparePassword(password, users[0].password)]);
}
}).then(([users, isMatch]) => {
if (isMatch) done(null, users);
else throw new Error('invalid password');
}).catch(err => {
done(null, false, err)
});
});
const comparePassword = (candidatePassword, hash) => {
return new Promise((resolve, reject) => {
bcrypt.compare(candidatePassword, hash, (err, isMatch) => {
if (err) reject(err);
else resolve(isMatch);
});
});
};
Наиболее запутанной частью этого, вероятно, является строка
return Promise.all([users, comparePassword(password, users[0].password)]);
Это можно было бы упростить до
return comparePassword(password, users[0].password);
, если users
не нужно было передавать на следующий .then()
, так как он передается на done()
, если есть совпадение.Promise.all()
принимает массив обещаний и разрешает их перед вызовом следующего обратного вызова .then()
.users
не является обещанием, но оно неявно преобразуется в одно с внутренним значением Promise.resolve()
и передается вместе со значением, разрешенным из comparePassword()
.
. Для дальнейшего использования вы можетеопределили comparePassword()
, используя util.promisify()
:
const comparePassword = require('util').promisify(bcrypt.compare);