我如何使用arr.forEach来调用asynchronousJavaScript的redis调用?

我正在使用node.js和redis。 我有一堆key的redis数据库。 像这样的东西:

用户/克里斯/药水用户/皮特/药水用户/克里斯/种族用户/皮特/种族用户/克里斯/武器用户/皮特/武器

我想做一个redis调用,它检索所有的用户状态,把统计信息放到一个JS对象中,然后传递给客户端在浏览器中显示字符统计信息。 使用javascript我把用户名chris注入到redis调用中,像这样:

KEYS user/u/* 

它返回:

 1) "user/chris/weapon" 2) "user/chris/race" 3) "user/chris/potion" 

现在我可以迭代这些结果,用GET获取每个键的值,并创build一个javascript对象。 看起来超级简单,所以我写的代码。 我很快遇到了使用forEach的问题:

 var redis = require('redis'); var client = redis.createClient(); exports.getUserObject = function(requesteduser, callback) { var userstats = {}; // the object to hold the user stats once retrieved from the db client.KEYS('user/' + requesteduser + '/*', function(err, replies) { replies.forEach(function (reply, i) { client.GET(reply, function(err, value) { // get the key name so we can populate a js object var n = reply.lastIndexOf('/'); var key = reply.substring(n + 1, reply.length); userstats[key] = value; console.dir(userstats); callback(null, userstats); // parent expects (err, userstats) }); }); }); } 

运行时,输出是这样的:

 { weapon: 'twosword' } { weapon: 'twosword', race: 'elf' } { weapon: 'twosword', race: 'elf', potion: 'mana' } 

callback(null, userstats)被调用三次。 不止一次调用callback将会产生问题,因为最终callback会触发将数据发送到客户端的数据。

我想我知道发生了什么。 client.GET运行三次,因为我问它。 replies数组有三个元素,所以每次client.GET的结果都会被调用。

我需要做的是让forEach循环遍历所有的redis键,一旦完成,就调用一次callback函数。 我试着用promise来解决这个问题,然后用async来解决这个问题,因为async有async.each。 我被困在解决这两个问题。 我现在回到原点,我相信我必须做一些与forEach不同的事情来取得进展。

我怎样才能做到这一点?

由于您正在迭代replies ,因此您可以检查何时到达最后一个元素,并只在该实例中调用callback

 client.KEYS('user/' + requesteduser + '/*', function(err, replies) { replies.forEach(function (reply, i) { client.GET(reply, function(err, value) { // get the key name so we can populate a js object var n = reply.lastIndexOf('/'); var key = reply.substring(n + 1, reply.length); userstats[key] = value; console.dir(userstats); if (i == replies.length-1) callback(null, userstats); // parent expects (err, userstats) }); }); }); 

我知道帮助@Grimtech已经有点晚了,但是我最终还是会把我的意见留给最终到达这里的其他人:

首先,我宁愿以不同的方式模拟Grimtech的问题。 像这样的东西:

 client.hmset("user:chris", "weapon", "some weapon", "race", "some race", "potion", "some potion"); client.hmset("user:pete", "weapon", "same weapon", "race", "other race", "potion", "other potion"); 

然后,我会在Node中返回一个类似下面的json的方法,假设我可以有多个以“user:chris”开头的键:

 router.get('/users/:user_id', function(req, res, next) { var response = []; var client = redis.createClient(); client.keys("user:" + req.params.user_id + "*", function (err, users) { users.forEach(function (key, pos) { client.hgetall(key, function (err, user) { response.push(user); if (pos === users.length - 1) { res.json(response); client.quit(); } }); }); }); }); 

if(pos === users.length – 1)解决了asynchronous问题。

返回的json将拥有所有的“user:chris”属性,所以你可以在客户端浏览器中做任何你想做的事情。