我正在学习在nodejs和redis db中开发。我是快递框架。
问题:让我们在redis中说我有一些关键用户:id的哈希用户信息,比我上次登录的关键user_lastlogged:user_id而且我在user_favourites中有他最喜欢的项目:user_id。
我想呈现包含用户详细信息,上次登录时间和他的收藏的页面。节点js中的项目。
我会使用类似的东西,但当然它不会工作,因为方法回调是异步运行的。
var redis = require("redis");
var client = redis.createClient();
router.get('/', function (req, res, next) {
var userId='1';
var returnHtml = '';
client.hgetall('user:'+userId, function(err,objects){
returnHtml+=utils.inspect(objects);
});
client.hgetall('user_lastlogged:'+userId, function(err,objects){
returnHtml+=utils.inspect(objects);
});
client.hgetall('user_favourites:'+userId, function(err,objects){
returnHtml+=utils.inspect(objects);
});
res.send(returnHtml);
});
现在请忽略使用适当的redis数据类型等。
如何在node.js中解决这类任务?或者也许在快递js框架中(如果它有帮助)?
谢谢!
答案 0 :(得分:3)
在节点中,大多数代码都是异步的,因此您将经常遇到这个用例。
基本上,您应该使用回调来进行链式操作。
var redis = require("redis");
var client = redis.createClient();
router.get('/', function (req, res, next) {
var userId='1';
var returnHtml = '';
client.hgetall('user:'+userId, function(err,objects){
returnHtml+=utils.inspect(objects);
client.hgetall('user_lastlogged:'+userId, function(err,objects){
returnHtml+=utils.inspect(objects);
client.hgetall('user_favourites:'+userId, function(err,objects){
returnHtml+=utils.inspect(objects);
res.send(returnHtml);
});
});
});
});
正如你可以看到它的回调地狱般,你可以调查https://github.com/NodeRedis/node_redis#user-content-promises来宣传调用以使其更具可读性。
使用蓝鸟可能看起来像:
var bluebird = require('bluebird');
var redis = require('redis');
bluebird.promisifyAll(redis.RedisClient.prototype);
bluebird.promisifyAll(redis.Multi.prototype);
var client = redis.createClient();
router.get('/', function (req, res, next) {
var userId='1';
var returnHtml = '';
client.hgetallAsync('user:'+userId)
.then(function(objects){
returnHtml += utils.inspect(objects);
return client.hgetallAsync('user_lastlogged:'+userId);
})
.then(function(objects){
returnHtml+=utils.inspect(objects);
return client.hgetallAsync('user_favourites:'+userId);
})
.then(function(objects){
returnHtml+=utils.inspect(objects);
res.send(returnHtml);
})
.catch(function(err){
//manage error
});
});
答案 1 :(得分:2)
免责声明:我会用更清洁的承诺来解决这个问题。如果你很好奇,请问,我会提供答案。
但是,对于你的问题,这里:
router.get('/', function (req, res, next) {
var userId='1';
var returnHtml = '';
client.hgetall('user:'+userId, function(err,objects){
returnHtml+=utils.inspect(objects);
client.hgetall('user_lastlogged:'+userId, function(err,objects){
returnHtml+=utils.inspect(objects);
client.hgetall('user_favourites:'+userId, function(err,objects){
returnHtml+=utils.inspect(objects);
res.send(returnHtml);
});
});
});
});
更新:Bluebird的答案在另一篇文章中提供。我是Q用户,所以我会这样做:
var q = require('q');
var promiseHGetAll = function(key, htmlFragment){ //making a promise version for the function call.
if(!htmlFragment) htmlFragment=""; //optional argument, of course
var deferred = q.defer(); //a deferred is an object that has a promise in it. and some methods
client.hgetall(key,deferred.makeNodeResolver());
//makeNodeResolver is for node methods that have
//function(err,result) call back. if the function has an error,
//the promise will be rejected and err will be passed to it.
// if there is no err, the promise will be resolved and result
// will be passed to it.
return deferred.promise.then(function(objects){
//the first argument to then() is a function that is called
//if the promise succeeds. in this case, this is objects returned
// from Redis.
return htmlFragment + utils.inpect(objects);
// this function can return a promise or a value.
// in this case it is returning a value, which will be
// received by the next .then() in the chain.
});
}
router.get('/', function(req,res){
var userId = "1";
promiseGetAll("user"+userId).then(function(htmlFragment){
//this is called when the promise is resolved, and the
//utils.inspect(objects) is called and the return value is
//supplied to this then()
return promiseGetAll("user_lastlogged"+userId, htmlFragment);
//.then() functions can return a promise. in this case, the
// next .then will be called when this promise is resolved or rejected.
}).then(function(withUserLastLogged){
return promiseGetAll("user_favourites"+userId,withUserLastLogged);
}).then(function(returnHTML){
res.send(returnHTML);
}).catch(function(error){
//this will be called if there is an error in the node calls,
// or any of the previous .then() calls throws an exception,
// or returns a rejected promise. it is a sugar syntax for
// .then(null, function(err){..})
res.status(503).send(error);
}).done(); //throw an error if somehow something was escaped us. shouldn't happen because of catch, but force of habit.
})