同步读取数据库嵌套调用问题
发布于 6个月前 作者 shaoyun 354 次浏览 来自 问答

Redis在Nodejs下keys, get都是异步的, 遇到一个问题, 需要 通过 keys 获取所有的key, 然后遍历通过get拿到key的值, 但是get是异步的, 刚开始上手做Node开发,这下给难住了,寻求帮助,看一下的代码有什么问题

var Thenjs = require('thenjs');
var redis = require("redis");
var client = redis.createClient(6379,'127.0.0.1');
client.on('error',function(error){
        console.log(error);
});
var serviceUser = [];

function task(arg, callback) { 
  Thenjs.nextTick(function () {
    callback(null, arg);
  });
}

Thenjs(function (cont) {
    client.keys('PHPREDIS_SESSION:*', function (err, keys) {
        task(keys, cont);
    });
})
.then(function (cont, keys) {
    //console.log(keys);
    Thenjs.eachSeries(keys, function (cont2, value) {
        client.get(value, function(err, reply){
            task(reply, cont2);
        });
    })
    .then(function (cont2, result) {
        var sessionStr = result.toString();
        var reg = /account_name\|s:\d+:"([a-zA-Z0-9-_]+?)"/;
        var match = reg.exec(sessionStr);
        if(match) {
            serviceUser.push(match[1]);
        }
        console.log(match[1]);
    }).fin(cont);
})
.then(function(cont){
      console.log('1');
})
.fin(function (cont, error, result) {
  console.log('2');
  cont();
});

发现fin没有执行, 需要将里面嵌套的结果在外层的fin中获取, 或者是外层的fin能够执行, 嵌套的each中,只循环了一次, 求教了

目前个人理解Thenjs.series符合内部嵌套的使用场景,但是Thenjs.series中的参数是不确定数量的,怎么操作啊

Thenjs.series([
  function (cont) { task(88, cont); },
  function (cont) { cont(null, 99); }
])
.then(function (cont, result) {
  console.log(result);
});

2015-5-14 13:34:49 自己探索,改用bluebird解决

var redis = require("redis");
var Promise = require("bluebird");
var client = redis.createClient(6379,'127.0.0.1');
client.on('error',function(error){
        console.log(error);
});
var serviceUser = [];

var getServiceName = function(str) {
    var sessionStr = str.toString();
    var reg = /account_name\|s:\d+:"([a-zA-Z0-9-_]+?)"/;
    var match = reg.exec(sessionStr);
    if(match) {
        return match[1];
    } else {
        return false;
    }
};
Promise.promisifyAll(redis);
client.keysAsync('PHPREDIS_SESSION:*').then(function(keys){
    return keys;
}).each(function(key){
    return client.getAsync(key).then(function(val){
        var name = getServiceName(val);
        if( name !== false) {
            serviceUser.push(name);
        }
        console.log(name);
    });
}).then(function(){
    console.log(serviceUser);
});

注意each中的那个return这是关键,Promise.promisifyAll很强大,可以为模块所有的异步方法生成一个Promise版本方法, 例如 client.get对应 client.getAsync 可以看到代码简洁了许多

2015-5-18 11:31:08 ThenJs怎么实现总算是理解了,ThenJs的改进实现如下

var Thenjs = require('thenjs');
var   _ = require('underscore');

function getServiceName(str) {
    var sessionStr = str.toString();
    var reg = /account_name\|s:\d+:"([a-zA-Z0-9-_]+?)"/;
    var match = reg.exec(sessionStr);
    if(match) {
        return match[1];
    } else {
        return false;
    }
};

var redis = require("redis");
var client = redis.createClient(6379,'127.0.0.1');
client.on('error',function(error){
        console.log(error);
});

Thenjs(function (cont) {
    client.keys('PHPREDIS_SESSION:*', cont);
})
.then(function (cont, keys) {
    Thenjs.each(keys, function (cont2, key) {
         client.get(key, cont2)
    })
    .then(function(cont2,val){
        _.each(val, function(item){
             var name = getServiceName(item);
             console.log(name);
        })
        cont();
    })
})
.then(function (cont) {
    console.log('--- End ---');
});

详情请看个人博客

4 回复

是不是then里的也要加return Thenjs.each的原因?

@i5ting 不行啊,我就奇怪为什么fin不执行

@shaoyun 你精简一下代码,丢到github上,然后大家给你看看

ps 我一般用bluebird比较多

@i5ting 这个不会模拟啊,主要是redis的get操作是个异步的,如果嵌套用Thenjs.series不知道合适不,但是参数怎么传递是个问题

回到顶部