请教关于node异步循环的问题

李惟
  • 2.1k

代码很简单,如下:

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

请问如何解决?

回复
阅读 3.4k
2 个回答
  1. 安装万能的async:sudo npm install async
  2. 把代码改成:
var async = require('async');

...

async.detect(
  data, 
  function(ip, cb) {
    client.sismember(url+':ip', ip, function(err, mem) {
        console.log('redis:' + find);
        cb(!mem);
    });
  },
  function(result) {
    find = result;
    console.log(find);
});

可以看下github上async的文档。

心不在焉
  • 2k

q.js的解决方案

npm i q

var Q = require('q');
function find (data, url, timeout) {
    var deferred = Q.defer();
    var n = data.length;
    data.forEach(function (ip) {
        Q.ninvoke(client, 'sismember', url + ':ip', ip)
            .then(function (ret) {
                if(ret) {
                    deferred.resolve(ip);
                } else if (--n <= 0) {
                    deferred.reject(new Error('Not found!'));
                }
            });
    });
    return Q.timeout(defered.promise, timeout);
}
//以上只用写一次,以下是使用方法
find(data, url, 1000)
    .then(function (ip) {
        //成功找到
        console.log('redis:' + find);
    }).fail(function (reason) {
        //没找到或超时
    });
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏