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客户端更加同步,但它比注册回调函数(小)改进,使您的代码更具可读性。