4

我在理解异步函数时遇到了一些麻烦。我已经阅读了Mixu 的 Node Book中的章节,但我仍然无法理解它。

基本上我想请求一个资源(使用节点包cheerio),解析它以获取有效的 URL,并将每个匹配项添加到我的 redis 集setname

问题是最后它只是将第一个匹配添加到 redis 集中。

function parse(url, setname) 
{
    request(url, function (error, response, body) 
    {
        if (!error && response.statusCode == 200) 
        {
            $ = cheerio.load(body)

            // For every 'a' tag in the body
            $('a').each(function() 
            {
                // Add blog URL to redis if not already there.
                var blog = $(this).attr('href')
                console.log("test [all]: " + blog);

                // filter valid URLs
                var regex = /http:\/\/[^www]*.example.com\//
                var result = blog.match(regex);
                if(result != null) 
                {
                    console.log("test [filtered]: " + result[0]);

                    redis.sismember(setname, result[0], function(err, reply) 
                    {
                        if(!reply) 
                        {
                            redis.sadd(setname, result[0])
                            console.log("Added " + result[0])
                        }
                        redis.quit()    
                    })
                }
            })
        }
    })
}

我将非常感谢有关如何重新构建它的指针,以便 redis.sadd 方法使用正确的结果。

当前实现的输出如下所示:

test [all]: http://test1.example.com/
test [filtered]: http://test1.example.com/
...
Added http://test2.example.com/

所以它添加了 test1.example.com 但不打印“添加”行,它没有添加 test2.example.com 但它正在打印“添加”行。

谢谢!

4

1 回答 1

2

第一个问题是由redis.sismember()异步引起的:当它的回调被调用时,你已经覆盖了result变量,所以它将指向它拥有的最后一个值,而不是你调用时的值redis.sismember()

解决这个问题的一种方法是通过将异步函数包装在闭包中来创建一个新的作用域变量:

(function(result) {
  redis.sismember(setname, result[0], function(err, reply) {
    ...
  });
})(result);

另一种选择是创建一个用作回调的部分函数:

  redis.sismember(setname, result[0], function(result, err, reply) {
    ...
  }.bind(this, result));

我认为第二个问题是由redis.quit()被调用引起的,它在第一个sadd(). 你不是在检查err,但如果你这样做,它可能会告诉你更多。

于 2013-05-18T20:24:53.357 回答