我在理解异步函数时遇到了一些麻烦.我已经阅读了
Mixu’s Node Book章,但我还是无法绕过它.
基本上我想要一个ressource(使用节点包cheerio),解析它的有效URL并将每个匹配添加到我的redis set 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()异步引起的:当调用它的回调时,你已经覆盖了结果变量,因此它将指向它的最后一个值,而不是你调用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连接.你没有检查错误,但如果你这样做可能会告诉你更多.