为了账号安全,请及时绑定邮箱和手机立即绑定

如何处理依赖于另一个承诺的承诺循环

如何处理依赖于另一个承诺的承诺循环

MM们 2021-08-26 15:02:23
我是 JavaScript 新手,我在使用 promise 时遇到了麻烦。我正在使用 cloudcraper 来检索网页的 html 以从中抓取数据。我有一个简单的函数 - getData() - 它调用 cloudcraper.get() 并将 html 传递给 extract() 函数,该函数负责抓取数据。这是工作代码:const getData = function(pageUrl) {  var data;  return cloudscraper.get(pageUrl)    .then(function(html) {      data = extract(html);      return data;      })    .catch(function(err) {      // handle error    })}返回的“数据”对象包含我想要连接的 URL 数组,以便检索其他信息。该信息必须存储在同一个数据对象中。所以我想为数组中包含的每个 URL 再次调用 cloudcraper.get() 方法。我试过下面的代码:const getData = function(pageUrl) {  var data;  // first cloudscraper call:  // retrieve main html  return cloudscraper.get(pageUrl)    .then(function(html) {      // scrape data from it      data = extract(html);      for (let i = 0; i < data.array.length; ++i) {        // for each URL scraped, call cloudscraper        // to retrieve other data        return cloudscraper.get(data.array[i])          .then(function(newHtml) {            // get other data with cheerio            // and stores it in the same array            data.array[i] = getNewData(newHtml);          })          .catch(function(err) {            // handle error          })         }        return data;        })    .catch(function(err) {      // handle error    })}但它不起作用,因为在解决循环中的承诺之前返回数据对象。我知道可能有一个简单的解决方案,但我无法弄清楚,所以你能帮我吗?提前致谢。
查看完整描述

2 回答

?
12345678_0001

TA贡献1802条经验 获得超5个赞

这可以通过使用Promise.all, 和await/async

如果我的理解是正确的,您正在尝试执行以下步骤:

  1. 获取原始 HTML

  2. 提取一些 HTML(看起来你想要更多的 url)

  3. 对于提取的每个网址,您要重新调用 cloudscraper

  4. 将每次调用的结果放回到原始数据对象中。

const getData = async (pageUrl) => {

    const html = await cloudscraper.get(pageUrl);

    const data = extractHtml(html);

    const promises = data.array.map( d => cloudscraper.get(d));

    const results = await Promise.all(promises);

    // If you wanted to map the results back into the originaly data object

    data.array.forEach( (a, idx) => a = results[idx] );

    return data;

};


查看完整回答
反对 回复 2021-08-26
?
湖上湖

TA贡献2003条经验 获得超2个赞

避免此类问题的最佳方法是使用async/await,如评论中建议的那样。这是基于您的代码的示例:


const getData = async function(pageUrl) {

  var data;

  // first cloudscraper call:

  // retrieve main html

  try {

    const html = await cloudscraper.get(pageUrl);

    // scrape data from it

    data = extract(html);

    for (let i = 0; i < data.array.length; ++i) {

      // for each URL scraped, call cloudscraper

      // to retrieve other data

      const newHtml = await cloudscraper.get(data.array[i]);

      // get other data with cheerio

      // and stores it in the same array

      data.array[i] = getNewData(newHtml); // if getNewData is also async, you need to add await

    }

  } catch (error) {

    // handle error

  }

  return data;

}

// You can call getData with .then().catch() outside of async functions 

// and with await inside async functions


查看完整回答
反对 回复 2021-08-26
  • 2 回答
  • 0 关注
  • 159 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信