在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被调用的时候,你已经覆盖了result
variables,所以它会指向它的最后一个值,而不是你调用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
,但如果你这样做,可能会告诉你更多。