【问题标题】:How to return value from async/await function?如何从 async/await 函数返回值?
【发布时间】:2019-03-01 17:34:30
【问题描述】:

使用 puppeteer 将来自 2 个不同网页的数据收集到数组中以供以后比较。但是程序在继续执行之前不会等待返回的数组。

async function go(){
  try{
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto('www.webpage.com');

    const tds = await page.$$('td');
    const data = [];
    for (let i = 0; i < tds.length; i++){
      const td = tds[i];
      const tdcontent = await page.evaluate(td => td.innerText, td);
      if (tdcontent.length > 5) {
        data[i] = {"content": tdcontent};
      }
    }
    return data;
  } catch (e) {
     console.log(e);
  }
};

(async function main(){
  const returnedData = await go();
  console.log(returnedData.length);
})();

返回data.length 是0。 nodejs 新手,async 编程结构。我认为这是因为在返回 data 之前记录了 .length?

我如何以可以操作并完成比较的方式返回数据?

【问题讨论】:

  • 您使用await 的每个函数是否都返回一个仅在完成后才解析的承诺?
  • go 返回一个数组而不是 Promise。
  • @ktilcu go() 实际上返回一个Promise,它解析为array,因为它是async。
  • 你是对的。我的错误
  • 尝试记录等待变量以确保它们都已解决。然后在 for 循环中记录数据变量。

标签: node.js ecmascript-6 async-await puppeteer ecmascript-2017


【解决方案1】:

首先,您的page.$$() 函数中缺少撇号。您应该将其更改为:

const tds = await page.$$('td');

接下来,您尝试将一个不存在的变量传递给page.evaluate()。您可以通过传递 tds[i] 而不是 td 来解决此问题:

const tdcontent = await page.evaluate(td => td.innerText, tds[i]);

您的最终结果应如下所示:

const go = async () => {
  try {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();

    await page.goto('www.webpage.com');

    const tds  = await page.$$('td');
    const data = [];

    for (let i = 0; i < tds.length; i++) {
      const tdcontent = await page.evaluate(td => td.innerText, tds[i]);

      if (tdcontent.length > 5) {
        data[i] = {
          content: tdcontent,
        };
      }
    }

    return data;
  } catch (error) {
    console.log(error);
  }
};

(async function main() {
  const returnedData = await go();

  console.log(returnedData.length);
})();

如果您仍然遇到问题,您可能希望使用page.goto( ... , { waitUntil: 'networkidle0' }) 等到页面完全加载,或者使用page.waitForSelector() 等到有问题的元素添加到DOM:

await page.goto('www.webpage.com' , {
  waitUntil: 'networkidle0',
});
// ...
await page.waitForSelector('td');

【讨论】:

  • 重新分配tdcontent 不是问题。 const 的范围仅限于 for 循环,因此对于循环的每次调用,它都是不同的 tdcontent。
  • 抱歉,我发的晚了。为了简单起见,我解释了我的代码并错过了报价和 td 分配。我已经编辑了原件,以便在这些方面更好地反映我的代码。今晚我将尝试这些其他建议。谢谢
【解决方案2】:

在这种情况下,我尽量不使用page.$$。相反,我使用document.querySelectorAll 并通过元素映射并提取文本。

这里是修改后的代码:

const getTdData = async () => {
  try {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto("http://example.com");

    return page.evaluate(() => {
      // get all td elements
      const tdList = [...document.querySelectorAll("td")]; 
      return tdList.map(element => ({ content: element.textContent }));
    });
  } catch (e) {
    console.log(e);
  }
};

(async function main() {
  const returnedData = await getTdData();
  console.log(returnedData.length);
})();

【讨论】:

  • 我曾尝试使用cheerio 来代替.$$ 来操作DOM,但结果与使用.$$ 时的结果相同。但我会尝试使用你今晚展示的地图。谢谢
  • 这很棒。它产生了预期的结果
猜你喜欢
  • 2021-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-20
  • 1970-01-01
  • 2018-09-30
相关资源
最近更新 更多