【问题标题】:Running an async function fetching a site in a loop运行异步函数以循环获取站点
【发布时间】:2020-10-01 14:23:13
【问题描述】:

大家好,我正在抓取一个获取电影图片网址的网站/ 我有这些功能目前正在获取在循环外工作得很好的图像

 async function getPosterDB(imdbID) {
  const posterdbURL = "https://www.movieposterdb.com/search?q=";
  let poster = "";
  try {
    return fetch(`${posterdbURL}${imdbID}`)
      .then((response) => response.text())
      .then((body) => {
        const $ = cheerio.load(body);
        poster = $(
          "body > div.section > div > div > div.col-md-9 > div.pt-3 > div.row.mgrid > div > a > img"
        ).attr("src");
        if (poster) {
          poster = poster.replace("posters", "xl");
          poster = poster.replace("/s", "/xl");
        }
      });
  } catch (error) {
    console.log(error);
  }
  return poster;
}

问题是当我尝试让 url 通过循环运行时。我得到未定义或承诺 现在我在网上搜索,发现我应该使用 setTimeout 函数来延迟函数或 Promise.all() ,也许我错过了什么 函数代码在这里。

async function advancedSearchMovies(searchTerm) {
  const movies = [];
  let images = [];
  try {
    return await fetch(`${MovieAdvancedUrl}${searchTerm}`)
      .then((response) => response.text())
      .then(async (body) => {
        const $ = cheerio.load(body);
        $("#main > div > div.lister.list.detail.sub-list > div >").each(
          async function (i, elem) {
            let imdbID = $(elem)
              .find("div.lister-item-image.float-left > a")
              .attr("href")
              .match(/title\/(.*)\//)[1];
          
            )
              let poster = getPosterDB(imdbID)
              const movie = {
                imdbID: imdbID,
                title: title,
                poster
              };

              movies.push(movie);
            }
          }
        );
        const result = Promise.all(movies).then(data => { return data});
        return result;
      });
  } catch (error) {
    console.log(error);
  }
}

但我还是得到了回报,你知道吗?

{ imdbID: 'tt1185834', 标题:“星球大战:克隆人战争”, yearRun: '2008', 评级IMDB:'5.9', ratingMeta: '35', 摘要:“在共和国战胜克里斯托弗西斯之后,阿纳金和他的新徒弟阿索卡·塔诺必须营救被绑架的赫特人贾巴的儿子。政治阴谋使他们的任务变得复杂。”, 海报:承诺{待定} }

问题已修复: 我只是让函数返回一个承诺

async function getPosterDB(imdbID) {
return new Promise((resolve, reject) => {
  fetch(`${posterdbURL}${imdbID}`)
    .then((response) => response.text())
    .then((body) => {
      const $ = cheerio.load(body);
      poster = $(
        "body > div.section > div > div > div.col-md-9 > div.pt-3 > div.row.mgrid > div > a > img"
      ).attr("src");
      if (poster) {
        poster = poster.replace("posters", "xl");
        poster = poster.replace("/s", "/xl");
      }
      setTimeout(() => {
        resolve(poster);
      }, 1000);
    });
});
}

然后当我这样称呼它时:

const images = await Promise.all(
          movies.map((element) =>
            getPosterDB(element.imdbID).then((data) => {
              return data;
            })
          )
        );
        movies.forEach((element, index) => {
          element.poster = images[index];
        });
        return movies;
      });

【问题讨论】:

  • 第二个版本看起来不错,正如您所观察到的,它返回了一个 Promise。所以只需在结果上调用.then(...)
  • PS .then(data => { return data}) 什么都不做,因此可以删除。
  • 添加另一个 .then ( (final) => console.log(final)) 给出未定义

标签: javascript node.js loops async-await fetch


【解决方案1】:

您需要将 promise 放入要传递给 Promise.all 的数组中。您只是在推送电影对象,并且是异步执行的,因此当您调用 Promise.all 时,该数组仍然未填充。

我还建议在使用async/await 时避免使用.then() 调用:

async function advancedSearchMovies(searchTerm) {
  try {
    const response = await fetch(`${MovieAdvancedUrl}${searchTerm}`);
    const body = await response.text();
    const $ = cheerio.load(body);
    const promises = Array.from($("#main > div > div.lister.list.detail.sub-list > div >")).map(async elem => {
      const imdbID = $(elem)
        .find("div.lister-item-image.float-left > a")
        .attr("href")
        .match(/title\/(.*)\//)[1];
      const poster = await getPosterDB(imdbID)
      const movie = {
        imdbID,
        title,
        poster,
      };
      return movie;
    });
    const movies = await Promise.all(promises);
    return movies;
  } catch (error) {
    console.log(error);
  }
}

请注意,如果您无法真正处理错误,则不应使用try/catch 语法。记录它并返回 undefined 可能不是函数调用者所期望的。最好让异常冒泡。

关于getPosterDB,避免Promise constructor antipattern

async function getPosterDB(imdbID) {
  const response = await fetch(`${posterdbURL}${imdbID}`);
  const body = await response.text();
  const $ = cheerio.load(body);
  let poster = $(
    "body > div.section > div > div > div.col-md-9 > div.pt-3 > div.row.mgrid > div > a > img"
  ).attr("src");
  if (poster) {
    poster = poster.replace("posters", "xl");
    poster = poster.replace("/s", "/xl");
  }
  return poster;
}

【讨论】:

  • 仍然得到一个承诺,当我解决它时,我得到未定义。还尝试传递在循环期间做出的所有承诺的数组仍然没有。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 2020-07-26
  • 2020-03-07
  • 1970-01-01
相关资源
最近更新 更多