![](/img/trans.png)
[英]How to make subsequent http requests asynchronously inside a while loop without using promises and async/await?
[英]How to make multiple nested http requests with promises and async/await while web scraping
下面我有一個 Node.js function 向不同的 url 發出一系列請求,然后對於每個 url 我使用 Cheerio web 抓取庫循環遍歷 dom 上的元素並創建一個子數組。 在每個請求結束時(子數組已滿后),我想將該數組的內容推送到更大的數組,該數組在請求 scope 之外。
我正在嘗試的方法似乎沒有用。 看起來我無法從 then 塊內部訪問“allPlayers”。
function readPlayers(teamUrls){
const allPlayers = [];
teamUrls.forEach((teamUrl, i) => {
const options = {
gzip: true,
uri: teamUrl,
Connection: 'keep-alive',
transform: function (body) {
return cheerio.load(body);
}
};
request(options)
.then(($) => {
const team = [];
$('tbody').children('tr').each(function(j, element){
const playerName = $(element).children('td').eq(1).children('span').eq(1).find('a').text().trim();
const player = { 'playerName': playerName };
team.push(player);
});
allPlayers.push(team);
}).catch(err => console.log("error: " + err)) );
});
}
所以我想知道重寫這段代碼以使請求有效並用結果填充外部數組 (allPlayers) 的最佳方法。
我研究過嘗試將整個請求直接推入外部數組,但無濟於事。
在此示例中,我使用請求承諾來發出請求。
我研究過使用 Promise.map,我認為它適合這種情況。 然后我會返回整個請求(我認為),但我不完全理解在那種情況下我在做什么......或者它是否有效。
任何人都可以解釋這種情況下的范圍界定,為什么我不能像我正在嘗試的那樣做。
非常感謝
您必須記住,當您使用異步 function 時,您不能 go 返回到同步代碼執行。
這是您可以做到的方法之一。 它將並行獲取所有玩家:
async function readPlayers(teamUrls) {
const playerPromises = teamUrls.map((teamUrl, i) => {
const options = {
gzip: true,
uri: teamUrl,
Connection: 'keep-alive',
transform: function(body) {
return cheerio.load(body);
}
};
return request(options)
});
const players = await Promise.all(playerPromises);
return players.reduce((allPlayers, $) =>{
const team = [];
$('tbody').children('tr').each(function(j, element) {
const playerName = $(element).children('td').eq(1).children('span').eq(1).find('a').text().trim();
const player = { playerName: playerName };
team.push(player);
});
allPlayers.push(team);
return allPlayers;
},[])
}
您可以使用await readPlayers(array)
或readPlayers(array).then(allteamplayers=>{...})
注意:在當前代碼中,它將是一個二維數組,[[{p1:p1}..]、[{p2:p2}..]] 等
如果您使用 forEach,每個回調都將異步運行,您將無法等待它們。 您可以將其交換為 for 循環,將您的承諾收集到一個數組中,然后等待所有承諾的完成:
async function readPlayers(teamUrls) {
const allPlayers = [];
const allPromises = [];
for (var i = 0; i < teamUrls.length; i++) {
var teamUrl = teamUrls[i];
const options = {
gzip: true,
uri: teamUrl,
Connection: "keep-alive",
transform: function(body) {
return cheerio.load(body);
}
};
allPromises.push(
request(options)
.then($ => {
const team = [];
$("tbody")
.children("tr")
.each(function(j, element) {
const playerName = $(element)
.children("td")
.eq(1)
.children("span")
.eq(1)
.find("a")
.text()
.trim();
const player = { playerName: playerName };
team.push(player);
});
allPlayers.push(team);
})
.catch(err => console.log("error: " + err))
);
// wait untill all the promises resolve
await Promise.all(allPromises);
console.log(allPlayers);
return allPlayers;
}
}
然后你可以通過等待你的 function 來獲得所有玩家:
var allPlayers = await readPlayers(teamUrls);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.