2013-05-18 205 views
4

我在理解異步函數時遇到了一些麻煩。我已閱讀Mixu's Node Book中的章節,但我仍然無法將其包裹在頭上。在回調中調用異步函數

基本上我想請求一個資源(使用節點包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()被調用引起的,它會在第一個sadd()之後關閉Redis連接。你不檢查err,但如果你這樣做,它可能會告訴你更多。

+0

謝謝,我添加了閉包,並將'redis.quit()'移到了解析函數的末尾,現在一切都按預期工作。 – mediocre