2015-11-03 149 views
1

我正在使用cheerio,請求和Node.js.Node.js + Cheerio:循環內的請求

當我運行下面的腳本時,它以錯誤的順序輸出名稱。我相信它是由異步本質引起的,我怎樣才能使它以「正確」的順序工作?我需要使用同步軟件包還是有辦法以某種方式更改它,以便以同步方式工作?

app.get('/returned', function (req, res) { 
    for (var y = 0; y < 10; y++) { 
     var url = "http://example.com" + y + "/person.html"; 
     request(url, function (err, resp, body) { 
      $ = cheerio.load(body); 
      var links = $('#container'); 
      var name = links.find('span[itemprop="name"]').html(); // name 
      if (name == null) { 
       console.log("returned null"); 
      } else { 
       console.log(name); 
      } 

     }); 
    } 
}); 
+1

它取決於。你想要並行發送請求還是串行發送請求?如果您要求的服務器一次可以處理多個請求,那麼串行會比並行緩慢得多。可以並行處理它,同時仍然按照您想要的順序得到結果。 –

+0

並行。我認爲異步會完成這項工作(由@ dm03514回答),我會研究它。 – salep

+1

請注意,他的答案是串聯的,而不是平行的。但異步確實有並行選項,您只需以某種方式將結果以您想要的順序進行存儲,而不管它們將按順序調用。 –

回答

5

承諾使這個相對容易:

app.get('/returned', function (req, res) { 
    let urls = []; 
    for (let y = 0; y < 10; y++) { 
     urls.push('http://example.com' + y + '/person.html'); 
    } 
    Promise.all(urls.map(function (url) { 
     return new Promise(resolve, reject) { 
      request(url, function (err, resp, body) { 
       if (err) {return reject(err);} 
       let $ = cheerio.load(body); 
       let links = $('#container'); 
       let name = links.find('span[itemprop="name"]').html(); // name 
       resolve({name: name, links: links, url: url}); 
      }); 
     }); 
    }).then(function (result) { 
     result.forEach(function (obj) { 
      if (obj.name == null) { 
       console.log(obj.url, "returned null"); 
      } else { 
       console.log(obj.url, obj.name); 
      } 
     }); 
    }).catch(function (err) { 
     console.log(err); 
    }); 
}); 

我開始通過創建URL來獲得一個數組,然後我繪製了諾言的數組。當每個請求都完成後,我通過名稱,網址和鏈接解決了承諾。當所有的承諾都完成後,我便循環結果,而結果將按照原來的順序。這並行運行。

+0

非常感謝。 – salep

+0

「app.get('/ returned',...」是做什麼的?這是一個特定於此示例的目錄嗎?我試圖重新創建類似的東西。 – daneasterman

+0

...它創建一個路徑... –

1

不,你不應該使用同步包。最簡潔的方法是使用一個成熟的第三方庫。

我推薦異步。

async.series方法將按照給定順序執行所有請求函數,然後允許您註冊一個回調,以便在發出所有請求時或發生錯誤時觸發。

https://github.com/caolan/async#seriestasks-callback