Рефакторинг паспорта локальной стратегии с использованием Promisy. Проблема с .catch () - PullRequest
0 голосов
/ 08 ноября 2018

В приложении экспресс + паспорт + локальная стратегия я использую bcrypt для хеширования пароля, это работает:

var bcrypt = require('bcrypt-nodejs');

familySchema.pre('save', function(next) {
  var family = this;
  var SALT_FACTOR = 14;

  if (!family.isModified('password')) return next();

  bcrypt.genSalt(SALT_FACTOR, function(err, salt) {
    if (err) return next(err);

    bcrypt.hash(family.password, salt, null, function(err, hash) {
      if (err) return next(err);
      family.password = hash;
      next();
    });
  });
});

Затем я рефакторинг с использованием promisify и async/await:

const bcrypt = require('bcrypt-nodejs');
const util = require('util');
const bcryptGenSalt = util.promisify(bcrypt.genSalt);
const bcryptHash = util.promisify(bcrypt.hash);

familySchema.pre('save', async function(next) {
  var family = this;
  const SALT_FACTOR = 14;
  if (!family.isModified('password')) return next();
  const salt = await bcryptGenSalt(SALT_FACTOR).catch(next);
  const hash = await bcryptHash(family.password, salt, null).catch(next);
  family.password = hash;
  next();
});
  • Является ли этот рефакторинг действительно правильным?
  • Как я могу дважды проверить, что ошибки в bcryptGenSalt или bcryptHash правильно отлавливаются? Есть ли способ как-то "заставить" bcryptGenSalt выдать ошибку, для тестирования?

  • Следующий шаг, как я могу удалить два .catch(next), используя функцию wrapAsync util:

wrapAsync.js:

module.exports = fn => (req, res, next) => fn(req, res, next).catch(next);

Следующая попытка не работает, ошибка: family.isModified() не является функцией (вероятно, потому что this больше не прав). А что делать с аргументами wrapAsync, так как next должен быть третьим аргументом?

familySchema.pre(
  'save',
  wrapAsync(async function(req, res, next) {
    var family = this;
    const SALT_FACTOR = 14;
    debugger;
    if (!family.isModified('password')) return next();
    const salt = await bcryptGenSalt(SALT_FACTOR);
    const hash = await bcryptHash(family.password, salt, null);
    family.password = hash;
    next();
  })
);

1 Ответ

0 голосов
/ 08 ноября 2018

Рефакторинг некорректен, потому что после операторов .catch остальная часть функции продолжит работать. Так, например, если bcryptGenSalt выдает ошибку, вызывается next (из-за .catch(next)), но это также будет продолжаться со следующей строкой кода, до конца функции (где next вызывается снова) .

Как правило, в async функциях вы используете try/catch вокруг операторов, которые могут выдавать ошибки:

familySchema.pre('save', async function(next) {
  const SALT_FACTOR = 14;
  if (!this.isModified('password')) return next();
  try {
    const salt = await bcryptGenSalt(SALT_FACTOR);
    const hash = await bcryptHash(this.password, salt, null);
    this.password = hash;
    return next();
  } catch(err) {
    return next(err);
  }
});

Есть ли способ как-то "заставить" bcryptGenSalt выдать ошибку, для тестирования?

Это зависит от того, какие инструменты вы используете для тестирования, но есть такие пакеты, как sinon, которые могут заглушить существующие функции, чтобы вы могли контролировать, а затем выдавать ошибки, которые затем можно проверять.

...