同步调用redis方法

时间:2016-08-20 21:21:19

标签: node.js express redis

我正在学习在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框架中(如果它有帮助)?

谢谢!

2 个答案:

答案 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.
})