如何承诺等待所有对象完成然后推送到数组?

Posted

技术标签:

【中文标题】如何承诺等待所有对象完成然后推送到数组?【英文标题】:How to make promise to wait for all objects to be complete and then push to array? 【发布时间】:2021-03-22 12:30:33 【问题描述】:

getURL() 函数从原始 URL 创建一个抓取的 URL 数组。 getSubURL() 然后循环遍历该数组并抓取所有这些页面的 URL。目前,此代码可以很好地输出到控制台,但我不知道如何等待我的数据解析,因此我可以将所有收集的数据推送到单个数组。目前,当我尝试返回站点然后推送到数组时,它只推送最后一个值。我相信这是一个 promise.all(map) 的情况,但我不知道如何正确地写一个而不会出错。理想情况下,我完成的抓取可以在另一个函数中调用。可以的话请看一下

const cheerio = require('cheerio');
const axios = require('axios');

let URL = 'https://toscrape.com';

const getURLS = async () => 
  try 
    const res = await axios.get(URL);
    const data = res.data;
    const $ = cheerio.load(data);

    const urlQueue = [];

    $("a[href^='http']").each((i, elem) => 
      const link = $(elem).attr('href');
      if (urlQueue.indexOf(link) === -1) 
        urlQueue.push(link);
      
    );
    return urlQueue;
   catch (err) 
    console.log(`Error fetching and parsing data: `, err);
  
;

const getSubURLs = async () => 
  let urls = await getURLS();

  try 
    //loop through each url in array
    for (const url of urls) 
      //fetch all html from the current url
      const res = await axios.get(url);
      const data = res.data;
      const $ = cheerio.load(data);

      //create object and push that url into that object 
      let sites = ;
      sites.url = url;
      let links = [];
      //scrape all links and save in links array
      $("a[href^='/']").each((i, elem) => 
        const link = $(elem).attr('href');
        if (links.indexOf(link) === -1) 
          links.push(link);
        
        //save scraped data in object
        sites.links = links;
      );
      // returns list of url:'url', links:[link1,link2,link3]
      console.log(sites);
    
   catch (err) 
    console.log(`Error fetching and parsing data: `, err);
  
;

【问题讨论】:

【参考方案1】:

不要认为这是一个与 Promise 相关的问题。

您需要将sites 收集到一个在循环外初始化的数组中。然后当getSubURLs() 解析时,它会解析到你的数组:

const getSubURLs = async() => 
  let urls = await getURLS();
  let siteList = [];
  try 
    for (const url of urls) 
      //         :
      //         :
      //         :
      siteList.push(sites);
    
   catch (err) 
    console.log(`Error fetching and parsing data: `, err);
  
  return siteList; // array of objects
;

getSubURLs().then(console.log);

【讨论】:

以上是关于如何承诺等待所有对象完成然后推送到数组?的主要内容,如果未能解决你的问题,请参考以下文章

等待所有 firebase 调用使用 map 函数完成

如何等待所有节点流完成/结束?

redux thunk - 承诺完成后如何在嵌套数组中调度数据

等待多个承诺完成

等待所有异步请求在循环内完成[重复]

等待循环中调用的所有承诺完成