在callback中调用asynchronous函数

我在理解asynchronous函数时遇到了一些麻烦。 我已经阅读了Mixu的Node Book中的章节,但是我仍然无法将它包裹起来。

基本上我想请求一个资源(使用节点包cheerio ),parsing它的有效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,但它打印“添加”行。

谢谢!

第一个问题是由于redis.sismember()是asynchronous的:当它的callback被调用的时候,你已经覆盖了resultvariables,所以它会指向它的最后一个值,而不是你调用redis.sismember()那个值redis.sismember()

解决这个问题的方法之一是通过将asynchronous函数封装在闭包中来创build一个新的范围variables:

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

另一种select是创build一个用作callback的部分函数:

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

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