运行 之前异步不等待函数
Async not awaiting function before running
我正在尝试从我计算机上保存的 HTML 中解析规范网站。我可以根据要求 post 文件。
我已经筋疲力尽地试图弄清楚为什么它不会 运行 同步。评论应该首先记录 CCCC
,然后是 BBBB
,最后是 AAAA
。
我 运行ning 的代码不会在第一个障碍处等待(它首先打印 AAAA...
)。我使用 request-promise
不正确吗?这是怎么回事?
这是因为 cheerio
的 .each()
方法(我假设它是同步的)吗?
const rp = require('request-promise');
const fs = require('fs');
const cheerio = require('cheerio');
async function parseAutodeskSpec(contentsHtmlFile) {
const topics = [];
const contentsPage = cheerio.load(fs.readFileSync(contentsHtmlFile).toString());
const contentsSelector = '.content_htmlbody table td div div#divtreed0e338374 nobr .toc_entry a.treeitem';
contentsPage(contentsSelector).each(async (idx, topicsAnchor) => {
const topicsHtml = await rp(topicsAnchor.attribs['href']);
console.log("topicsHtml.length: ", topicsHtml.length);
});
console.log("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
return topics;
}
正如@lumio 在他的评论中所述,我还认为这是因为 each
函数是同步的。
您应该使用 map
方法,并在结果上使用 Promise.all()
以等待足够的时间:
const obj = contentsPage(contentsSelector).map(async (idx, topicsAnchor) => {
const topicsHtml = await rp(topicsAnchor.attribs['href']);
console.log("topicsHtml.length: ", topicsHtml.length);
const topicsFromPage = await parseAutodeskTopics(topicsHtml)
console.log("topicsFromPage.length: ", topicsFromPage.length);
topics.concat(topicsFromPage);
})
const filtered = Object.keys(obj).filter(key => !isNaN(key)).map(key => obj[key])
await Promise.all(filtered)
console.log("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
这样试试:
let hrefs = contentsPage(contentsSelector).map((idx, topicsAnchor) => {
return topicsAnchor.attribs['href']
}).get()
let topicsHtml
for(href of hrefs){
topicsHtml = await rp(href);
console.log("topicsHtml.length: ", topicsHtml.length);
}
现在 await 在 map 之外,或者每个都不像你想的那样工作。
根据这里的其他答案,我得出了一个相当优雅的结论。注意在 .map()
回调中避免 async
/await
,作为 cheerio
的回调(以及我从 async
/await
,通常所有回调) 似乎不尊重 await
的同步性质:
async function parseAutodeskSpec(contentsHtmlFile) {
const contentsPage = cheerio.load(fs.readFileSync(contentsHtmlFile).toString());
const contentsSelector = '.content_htmlbody table td div div#divtreed0e338374 nobr .toc_entry a.treeitem';
const contentsReqs = contentsPage(contentsSelector)
.map((idx, elem) => rp(contentsPage(elem).attr('href')))
.toArray();
const topicsReqs = await Promise.all(contentsReqs)
.map(req => parseAutodeskTopics(req));
return await Promise.all(topicsReqs);
}
我正在尝试从我计算机上保存的 HTML 中解析规范网站。我可以根据要求 post 文件。
我已经筋疲力尽地试图弄清楚为什么它不会 运行 同步。评论应该首先记录 CCCC
,然后是 BBBB
,最后是 AAAA
。
我 运行ning 的代码不会在第一个障碍处等待(它首先打印 AAAA...
)。我使用 request-promise
不正确吗?这是怎么回事?
这是因为 cheerio
的 .each()
方法(我假设它是同步的)吗?
const rp = require('request-promise');
const fs = require('fs');
const cheerio = require('cheerio');
async function parseAutodeskSpec(contentsHtmlFile) {
const topics = [];
const contentsPage = cheerio.load(fs.readFileSync(contentsHtmlFile).toString());
const contentsSelector = '.content_htmlbody table td div div#divtreed0e338374 nobr .toc_entry a.treeitem';
contentsPage(contentsSelector).each(async (idx, topicsAnchor) => {
const topicsHtml = await rp(topicsAnchor.attribs['href']);
console.log("topicsHtml.length: ", topicsHtml.length);
});
console.log("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
return topics;
}
正如@lumio 在他的评论中所述,我还认为这是因为 each
函数是同步的。
您应该使用 map
方法,并在结果上使用 Promise.all()
以等待足够的时间:
const obj = contentsPage(contentsSelector).map(async (idx, topicsAnchor) => {
const topicsHtml = await rp(topicsAnchor.attribs['href']);
console.log("topicsHtml.length: ", topicsHtml.length);
const topicsFromPage = await parseAutodeskTopics(topicsHtml)
console.log("topicsFromPage.length: ", topicsFromPage.length);
topics.concat(topicsFromPage);
})
const filtered = Object.keys(obj).filter(key => !isNaN(key)).map(key => obj[key])
await Promise.all(filtered)
console.log("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
这样试试:
let hrefs = contentsPage(contentsSelector).map((idx, topicsAnchor) => {
return topicsAnchor.attribs['href']
}).get()
let topicsHtml
for(href of hrefs){
topicsHtml = await rp(href);
console.log("topicsHtml.length: ", topicsHtml.length);
}
现在 await 在 map 之外,或者每个都不像你想的那样工作。
根据这里的其他答案,我得出了一个相当优雅的结论。注意在 .map()
回调中避免 async
/await
,作为 cheerio
的回调(以及我从 async
/await
,通常所有回调) 似乎不尊重 await
的同步性质:
async function parseAutodeskSpec(contentsHtmlFile) {
const contentsPage = cheerio.load(fs.readFileSync(contentsHtmlFile).toString());
const contentsSelector = '.content_htmlbody table td div div#divtreed0e338374 nobr .toc_entry a.treeitem';
const contentsReqs = contentsPage(contentsSelector)
.map((idx, elem) => rp(contentsPage(elem).attr('href')))
.toArray();
const topicsReqs = await Promise.all(contentsReqs)
.map(req => parseAutodeskTopics(req));
return await Promise.all(topicsReqs);
}