Async не ожидает функции перед запуском - PullRequest
0 голосов
/ 06 ноября 2018

Я пытаюсь проанализировать веб-сайт спецификации из сохраненного HTML на моем компьютере. Я могу опубликовать файл по запросу.

Я сгорел, пытаясь понять, почему он не работает синхронно. Комментарии должны регистрировать сначала CCCC, затем BBBB, затем, наконец, один AAAA.

Код, который я запускаю, не будет ждать первого препятствия (сначала он печатает AAAA...). Я неправильно использую request-promise? Что происходит?

Это из-за .each() метода cheerio (я предполагаю, что он синхронный)?

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;
}

Ответы [ 3 ]

0 голосов
/ 07 ноября 2018

Попробуйте так:

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);
}

Теперь ожидание находится за пределами карты или каждого, который не совсем работает так, как вы думаете.

0 голосов
/ 07 ноября 2018

Основываясь на других ответах, я пришел к довольно элегантному выводу. Обратите внимание на избегание async / await в обратном вызове .map(), так как обратные вызовы 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);
}
0 голосов
/ 06 ноября 2018

Как сказал @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");
...