请教关于Nodejs异步循环的问题
请教关于Nodejs异步循环的问题
代码很简单,如下:
var find;
data.some(function(ip) {
client.sismember(url+':ip', ip, function(err, mem) {
!mem && (find = ip);
console.log('redis:' + find);
});
console.log(find);
return find;
});
原理很简单:
- 我先some循环一个IP数组
- 如果数组中的IP不存在redis中,我就将find赋值为当前IP
- 如果循环过程中找到了IP,我就跳出循环,不再一直查询redis
结果,代码中有两个console:
- 先循环数组数据,find一直是undefined,因此不会跳出循环
- 之后执行所有redis查询结果,并重复给find复制,并打印出来
问题:
- 首先结果不是我想要的
- 效率差,我循环100条就查询100次redis
请问如何解决?
9 回复
不知所云
楼主是否需要如下两个函数?:
函数1):检查指定的IP数组是否存在于redis中,返回所有不存在于redis中的IP数组: 函数2):将指定的IP数组存放于redis中
async.js async.parallelLimit(…) 不知是否能解决你的问题
async.mapSeries将执行转成同步,可以试试
两个办法 要么转同步 . 要么回调函数里加上状态判断 . 建议第二种方式 .
var find;
var howdo = require('howdo');
howdo.each(data, function(index, ip, done){
if(find){
return done(null);
}
client.sismember(url+':ip', ip, function(err, mem) {
if(err){
return done(err);
}
if(!mem){
find = ip;
console.log('redis:' + find);
}
done(null);
});
}).together(function(err){
if(err){
return console.log(err);
}
console.log(find);
});
https://github.com/alsotang/async_demo 来学习一下 async
你的代码中存在的主要问题是 client.sismember
是一个异步操作,而你在 data.some
中使用了同步的循环逻辑。这导致了你看到的结果并不是你预期的那样。你希望在找到匹配项后能够提前退出循环,而不是每次循环都完成后再处理结果。
解决方案
你可以使用递归或异步迭代器来实现这一需求。这里我们用递归的方法来解决这个问题:
function checkIPs(ips, index = 0, client, url, callback) {
if (index >= ips.length) {
return callback(null, null); // 所有IP都已经检查过,没有找到
}
const ip = ips[index];
client.sismember(url + ':ip', ip, function(err, mem) {
if (err) return callback(err);
if (!mem) { // 如果IP不存在于集合中
return callback(null, ip); // 返回当前IP并停止进一步的检查
}
// 否则继续检查下一个IP
checkIPs(ips, index + 1, client, url, callback);
});
}
// 使用方法:
checkIPs(data, 0, client, url, function(err, find) {
if (err) throw err;
console.log('发现的IP:', find);
});
解释
- 递归函数:
checkIPs
函数递归地遍历IP数组,直到找到第一个不在集合中的IP或者遍历完所有IP。 - 回调机制:当找到符合条件的IP时,立即调用回调函数并返回该IP,从而避免不必要的后续检查。
- 错误处理:在每个回调函数内部处理可能发生的错误。
这种方法确保了在找到第一个符合条件的IP时能够立即停止检查,并且提高了整体效率,因为你不需要等待所有的异步操作完成。