2013-05-18 3 views
4

У меня возникли проблемы с пониманием асинхронных функций. Я прочитал главу в Mixu's Node Book, но я все еще не могу обернуть вокруг себя.Вызов асинхронной функции в обратном вызове

В принципе, я хочу запросить ressource (используя пакет узла 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(), который закрывает соединение Redis после первого sadd(). Вы не проверяете err, но если вы это сделаете, это может рассказать вам больше.

+0

Спасибо, я добавил закрытие и переместил 'redis.quit()' в конец функции синтаксического анализа, и теперь все работает так, как ожидалось. – mediocre

Смежные вопросы