我在理解异步函数时遇到了一些困难。我已阅读 Mixu's Node Book 中的章节但我仍然无法理解它。
基本上我想请求一个资源(使用 Node 包 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 但它打印了“添加”行。
谢谢!
最佳答案
第一个问题是由 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
,但如果您这样做,它可能会告诉您更多信息。
关于javascript - 在回调中调用异步函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16628483/