2013-05-18 167 views
4

我在理解异步函数时遇到了一些麻烦。我已阅读Mixu's 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但它的为它打印“添加”行。

谢谢!

回答

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()之后关闭Redis连接。你不检查err,但如果你这样做,它可能会告诉你更多。

+0

谢谢,我添加了闭包,并将'redis.quit()'移到了解析函数的末尾,现在一切都按预期工作。 – mediocre