Сделать Node Redis get() синхронным

я только начал внедрять Redis с Node. во время реализации метода аутентификации мне нужно проверить, существует ли токен в Redis, если не обновить новый токен в Redis и в моей базе данных mongo, для этого мне нужно написать большой блок обратного вызова и не получить результат должным образом. как мы можем заставить Redis краснеть от обратных вызовов. как мы можем сделать его синхронным. пример кода ниже.

module.exports.authenticate = function(request, response)   {
    var reply = {};

    if(UserSchema)  {
        var UserModel, attributes;

        /** Registering User Model; **/
        mongoose.model('user', UserSchema);
        UserModel = mongoose.model('user');

        attributes = request.params;

        UserModel.findOne(attributes, "_id name email token", function(error, user) {

            if(!error && user)  {
                var token;

                //delete user.password;
                token = user.token;

                /** Checking token exists in redis; **/
                redisClient.get(token, function(error, value)   {
                    if(value === null && error === null)    {

                        /** Creating new token; **/
                        token = require('crypto').createHash('md5').update("" + (new Date()).getTime()).digest("hex");
                        user.token = token;

                        /** Storing new token on redis; **/
                        setTokenOnRedis(token);

                        /** Updating token in the user model; **/
                        UserModel.update({ _id : user._id}, { token : token }, function(error, user)    {
                            if(error !== null && user === null) {
                                deleteTokenOnRedis(token);

                                /** Error message; **/
                                reply = {
                                    error : true,
                                    code : "AUTH#001",
                                    msg : "User authentication failed, Please check user credentials."
                                }
                                response.send(reply);

                            }else if(error === null && user !== null)   {
                                reply = user;
                                response.send(reply);
                            }
                        });
                    }else if(value !== null)    {
                        reply = user;
                        response.send(reply);
                    }else   {
                        /** Error message; **/
                        reply = {
                            error : true,
                            code : "AUTH#001",
                            msg : "User authentication failed, Please check user credentials."
                        };
                        response.send(reply);
                    }
                });
            }else   {
                /** Error message; **/
                reply = {
                    error : true,
                    code : "AUTH#001",
                    msg : "User authentication failed, Please check user credentials."
                }
            }       
        });
    }else   {

        /** Error message; **/
        reply = {
            error : true,
            code : "AUTH#001",
            msg : "User authentication failed, Please check user credentials."
        }

        response.send(reply);
    }
};

person Jaison Justus    schedule 11.12.2012    source источник


Ответы (2)


Нет, вы не сможете синхронизировать вызовы ввода-вывода, включая вызовы Redis. Единственные доступные синхронные вызовы ввода-вывода, о которых я знаю, - это вызовы файловой системы и консоли.

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

  • вернуться раньше, сначала проверив ошибку.
  • вынести повторяющийся код в отдельную функцию, например, создание структур ошибок.
  • используйте эту асинхронную библиотеку: https://github.com/caolan/async. В частности, здесь может пригодиться функция водопада.

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

  • setTokenOnRedis (токен);
  • удалитьTokenOnRedis (токен);

Я реорганизовал ваш пример кода, который, надеюсь, должен быть менее отступным и более читабельным/поддерживаемым. Я не использовал асинхронность, я оставлю это вам.

Лично я нашел модель асинхронного кодирования всего узла поначалу очень неприятной, но к ней можно привыкнуть. Через некоторое время вы научитесь использовать различные шаблоны асинхронного кодирования, и тогда это станет почти терпимо :)

Некоторые ссылки, которые могут оказаться полезными:

рефакторинг кода:

module.exports.authenticate = function(request, response){
  authenticate(request, response, function(err, reply){
    if(err){
       reply = authenticationError(err);
    }
    response.send(reply);
  });
};

var authenticationError = function(internalmsg){
  return {
    internalmsg : internalmsg,
    error : true,
    code : "AUTH#001",
    msg : "User authentication failed, Please check user credentials."
  };
};

var authenticate = function(request, response, callback)   {
  if(UserSchema)  {
    var UserModel, attributes;

    /** Registering User Model; **/
    mongoose.model('user', UserSchema);
    UserModel = mongoose.model('user');

    attributes = request.params;

    UserModel.findOne(attributes, "_id name email token", function(err, user) {
      if(err || !user){
        return callback(err || "UserModel.findOne, no user");
      }

      var token;

      //delete user.password;
      token = user.token;

      /** Checking token exists in redis; **/
      redisClient.get(token, function(err, value){
        if(err){
          return callback(err);
        }
        if(value){
          return callback(null, value);
        }

        /** Creating new token; **/
        token = require('crypto').createHash('md5').update("" + (new Date()).getTime()).digest("hex");
        user.token = token;

        /** Storing new token on redis; **/
        setTokenOnRedis(token);

        /** Updating token in the user model; **/
        UserModel.update({ _id : user._id}, { token : token }, function(err, user) {
          if(err || !user) {
            deleteTokenOnRedis(token);
            return callback(err || "UserModel.update, no user found");
          }
          callback(null, user);
        });
      });
    });
  }
};
person AndyD    schedule 12.12.2012
comment
спасибо за преломленный код. точки, которые вы наметили, - это именно то, что я ищу. - person Jaison Justus; 16.12.2012

Спустя много лет после первоначального вопроса клиент Redis для Node.js остается асинхронным по своей природе и вряд ли изменится.

Но для более удобного использования этого способа работы пакет поддерживает промисы, как описано в http://redis.js.org/#redis-a-nodejs-redis-client-usage-example-обещания.

Это не делает Node.js более синхронным или клиентом Redis, но это (небольшое) улучшение по сравнению с регистрацией функций обратного вызова, делающее ваш код немного более читабельным.

person Jochem Schulenklopper    schedule 30.04.2018