当前位置:嗨网首页>书籍在线阅读

18-使用方法

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

5.4.2 使用方法

首先加载ioredis模块:

var Redis = require('ioredis');

下面的代码将创建一个默认连接到地址127.0.0.1,端口6379的Redis连接:

var redis = new Redis();

也可以显式地指定需要连接的地址:

var redis = new Redis(6379, '127.0.0.1');

由于Node.js的异步特性,在处理返回值的时候与其他客户端差别较大。还是以 GET/ SET 命令为例:

redis.set('foo', 'bar', function () {
  // 此时SET命令执行完并返回结果,
  // 因为这里并不关心SET命令的结果,所以我们省略了回调函数的形参。
  redis.get('foo', function (error, fooValue) {
  // error参数存储了命令执行时返回的错误信息,如果没有错误则返回null。
  // 回调函数的第二个参数存储的是命令执行的结果
  console.log(fooValue); // 'bar'
  });
});

使用ioredis执行命令时需要传入回调函数(callback function)来获得返回值,当命令执行完返回结果后ioredis会调用该函数,并将命令的错误信息作为第一个参数、返回值作为第二个参数传递给该函数。同时ioredis还支持Promise形式的异步处理方式,如果省略最后一个回调函数,命令语句会返回一个Promise值,如:

redis.get('foo').then(function (fooValue) {
  // fooValue 即为键值
});

关于Node.js的异步模型的介绍超出了本书的范围,有兴趣的读者可以访问Node.js的官方网了解更多信息。

Node.js的异步模型使得通过ioredis调用Redis命令的表现与Redis的底层管道协议十分相似:调用命令函数时(如 redis.set() )并不会等待Redis返回命令执行结果,而是直接继续执行下一条语句,所以在Node.js中通过异步模型就能实现与管道类似的效果。上面的例子中我们并不需要 SET 命令的返回值,只要保证 SET 命令在 GET 命令前发出即可,所以完全不用等待 SET 命令返回结果后再执行 GET 命令。因此上面的代码可以改写成:

// 不需要返回值时可以省略回调函数
redis.set('foo', 'bar');
redis.get('foo', function (error, fooValue) {
   console.log(fooValue); // 'bar'
});

不过由于 SETGET 并未真正使用Redis的管道协议发送,所以当有多个客户端同时向Redis发送命令时,上例中的两个命令之间可能会被插入其他命令,换句话说, GET 命令得到的值未必是“bar”。

虽然Node.js的异步特性给我们带来了相对更高的性能,然而另一方面使用Redis实现某个功能时我们经常需要读写若干个键,而且很多情况下都会依赖之前命令的返回结果。这时就会出现嵌套多重回调函数的情况,影响代码可读性。就像这样:

redis.get('people:2:home', function (error, home) {
  redis.hget('locations', home, function (error, address) {
  redis.exists('address:' + address, function (error, addressExists) {
    if (addressExists) {
    console.log('地址存在。');
    } else {
    redis.exists('backup.address:' + address, function (error, backupAddress Exists) {
      if (backupAddressExists) {
      console.log('备用地址存在。');
      } else {
      console.log('地址不存在。');
      }
    });
    }
  });
  });
});

上面的代码并不是极端的情况,相反在实际开发中经常会遇到这种多层嵌套。为了减少嵌套,可以考虑使用Async10、Step11等第三方模块。如上面的代码可以稍微修改后使用Async重写为:

10 https://github.com/caolan/async

11 https://github.com/creationix/step

async.waterfall([
  function (callback) {
  redis.get('people:2:home', callback);
  },
  function (home, callback) {
  redis.hget('locations', home, callback);
  },
  function (address, callback) {
  async.parallel([
    function (callback) {
    redis.exists('address:' + address, callback);
    },
    function (callback) {
    redis.exists('backup.address:' + address, callback);
    },
  ], function (err, results) {
    if (results[0]) {
    console.log('地址存在。');
    } else if (results[1]) {
    console.log('备用地址存在。');
    } else {
    console.log('地址不存在。');
    }
  });
  }
]);

另外,可以使用co12模块借助ES6的Generator特性来将ioredis的返回结果“串行化”:

12 https://github.com/tj/co

var co = require('co');
co(function* () {
  var result = yield redis.get('foo');
  return result;
}).then(function (fooValue) {
  console.log(fooValue);
});