Async Await | Сервер не может дождаться ответа от базы данных, прежде чем использовать аутентификацию - PullRequest
0 голосов
/ 01 июля 2019

Итак, у меня проблема, когда я пытаюсь сделать асинхронный вызов в моей базе данных, чтобы проверить, существуют ли имя пользователя и пароль учетной записи, а затем проверить, действительны ли они.

Я столкнулся с проблемой, что сервер пропускает мой вызов базы данных, а затем переходит к проверке, прежде чем информация из базы данных будет получена.

Код:

class HandlerGenerator {
  login (req, res) {
    let username = req.body.username;
    let password = req.body.password;
    let checkUsername = "";
    let checkPassword = "";

    var lData = {
        username: req.body.username,
        password: req.body.password
      };
    // For the given username fetch user from DB
    var db = req.db;
    var getUser = async () => {
        var result = await (
          User.findOne(lData , function(err, userLogin){
              if(err){
                console.log(err);
                return
              }
              console.log(userLogin);
              console.log("------====----");
              console.log(userLogin.username);
              checkUsername = userLogin.username;
              checkPassword = userLogin.password;

              console.log("------====----");
              console.log(checkUsername);
              console.log(checkPassword);
            })
        );
        console.log("--00--");
        console.log('result' + result)
        return result;
    };

    console.log("does this work?");
    if (username && password) {
      console.log("------==2==----");
      console.log(checkUsername)
      console.log(checkPassword)
      if (username === checkUsername && password === checkPassword) {
        let token = jwt.sign({username: username},
          config.secret,
          { expiresIn: '24h' // expires in 24 hours
          }
        );
        // return the JWT token for the future API calls
        res.json({
          success: true,
          message: 'Authentication successful!',
          token: token
        });
      } else {
        res.send(403).json({
          success: false,
          message: 'Incorrect username or password'
        });
      }
    } else {
      res.send(400).json({
        success: false,
        message: 'Authentication failed! Please check the request'
      });
    }
  }
  index (req, res) {
    res.json({
      success: true,
      message: 'Index page'
    });
  }
}

Когда я запускаю это "Это работает?" Комментарий всегда выполняется первым, и я запутался в том, что я испортил

1 Ответ

1 голос
/ 01 июля 2019

У вас есть две основные проблемы здесь.

Сначала async возвращает AsyncFunction, который возвращает Promise при вызове. Это означает, что на данный момент ничего в getUser не было выполнено. Мало того, что вы действительно должны вызвать getUser, чтобы начать выполнение того, что находится внутри него, но вам также нужно дождаться результата, иначе у вас нет абсолютно никаких гарантий, что выполнение будет закончено. Вместо того, чтобы преодолевать эту проблему, сделать вашу login функцию async более разумным выбором, поскольку вы пытаетесь выполнять внутри нее асинхронные операции. Затем вы можете удалить функцию getUser и оставить только часть var result = await User.findOne(....).

Другая проблема, как сказали несколько человек в комментариях, заключается в том, что вам нужно await на Promise. Глядя на ваш вызов функции, похоже, что ваши findOne функции используют обратный вызов, а не обещание. Проверьте документацию, некоторые библиотеки поддерживают оба и могут действительно вернуть обещание, если вы не передадите какой-либо обратный вызов. Если это произойдет, вы не должны передавать обратный вызов. Результат ожидаемого вызова должен быть userLogin.

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

// this is the function that we want to wrap
function funcToWrap(someParam, callback) {
   // does stuff
   callback(null, "some result");
}

// this is the wrapper
function wrappedFunction(someParam) {
  return new Promise((resolve, reject) => {
    funcToWrap(someParam, (err, res) => {
      if (err === null) {
        reject(err);
      } else {
        resolve(res);
      }
    });
  });

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

Это настолько распространенный шаблон, что многие библиотеки уже реализуют эту функцию. Например, библиотека Promise Bluebird предоставляет функцию promisify, которая делает именно это. http://bluebirdjs.com/docs/api/promise.promisify.html

Таким образом, вместо того, чтобы писать все это самостоятельно, вы можете просто написать

var wrappedFunction = Promise.promisify(funcToWrap);
...