关于node.js:使节点Redis get()同步

Make Node Redis get() Synchronous

我刚开始用node实现redis。 在身份验证方法的实现过程中,我需要检查令牌是否存在于redis中,如果没有在redis和我的mongo db中更新新令牌,我需要编写一个大的回调块并且不能正确获取结果。 我们怎样才能使redis变回红色回调。 我们怎样才能使它同步。 示例代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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);
    }
};


不,你将无法使任何io调用同步,包括redis。我所知道的唯一同步io调用是文件系统和控制台调用。

但是,您可以使用一些编码技术使异步编码更易于管理。

  • 通过首先检查错误来提前返回。
  • 将重复代码移动到单独的函数中,例如,创建错误结构。
  • 使用此异步库:https://github.com/caolan/async。特别是瀑布函数在这里可能很方便。

我还认为你需要传递一个回调方法这些函数,因为它们是异步的。

  • setTokenOnRedis(令牌);
  • deleteTokenOnRedis(令牌);

我已经重构了你的示例代码,希望它应该更少缩进,更易读/可维护。我没有使用异步,我会把它留给你。

就个人而言,我发现整个节点异步编码模型最初非常令人沮丧,但你已经习惯了。过了一段时间,你学习使用各种异步编码模式然后它变得可以容忍:)

您可能会发现一些有用的链接:

  • 异步node.js调用中的错误处理
  • Node.js最佳实践异常处理
  • 如何避免在Node.js中长时间嵌套异步函数

重构代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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);
        });
      });
    });
  }
};


在原始问题之后的许多年,Node.js的Redis客户端本质上仍然是异步的 - 而且它不太可能改变。

但是为了更方便地处理这种工作方式,该软件包支持promises,如http://redis.js.org/#redis-a-nodejs-redis-client-usage-example-promises中所述。

它不会使Node.js更加同步,也不会使Redis客户端更加同步,但它比注册回调函数(小)改进,使您的代码更具可读性。