NodeJS 使用Cheerio抓取subreddit的异步函数返回undefined

toe95027  于 2023-01-16  发布在  Node.js
关注(0)|答案(1)|浏览(140)

脚本本身运行良好(手动输入url,使用fs模块节点script_name. js编写json文件),但在Express get请求中,它返回undefined。
所以我构建了一个简单的前端,让用户输入要抓取的subreddit名称。问题就在这里:

Express控制器
const run = require("../run");
requestPosts: async (req, res) => {
    try {
      const { subreddit } = req.body;
      const response = await run(subreddit);
      //console.log(response);
      res.json(response);
    } catch (error) {
      console.error(error);
    }
  },
加油功能
const axios = require("axios");
const { load } = require("cheerio");
let posts = [];

async function getImage(postLink) {
  const { data } = await axios(postLink);
  const $ = load(data);
  return $("a.post-link").attr("href");
}

async function run(url) {
  try {
    console.log(url);
    const { data } = await axios(url);
    const $ = load(data);
    $(".thing.linkflair.link").map(async (i, e) => {
      const title = $(e)
        .find(".entry.unvoted .top-matter .title .title")
        .text();
      const user = $(e)
        .find(".entry.unvoted .top-matter .tagline .author")
        .text();
      const profileLink = `https://old.reddit.com/user/${user}`;
      const postLink = `https://old.reddit.com/${$(e).find("a").attr("href")}`;
      // const thumbail = $(e).find("a img").attr("src");
      const image = await getImage(postLink);
      posts.push({
        id: i + 1,
        title,
        postLink,
        image,
        user: { user, profileLink },
      });
    });
    const nextPage = $(".next-button a").attr("href");
    if (nextPage) {
      await run(nextPage);
    } else {
      return posts;
    }
  } catch (error) {
    console.error(error);
  }
}

module.exports = run;

我试过使用Promise((resolve,reject)=〉{}),我认为它返回undefined是因为代码可能不同步。
(idk如果有意义的话,我刚开始编程)

8gsdolmq

8gsdolmq1#

.map()不支持承诺,也不等待您的承诺完成。因此,$(".thing.linkflair.link").map()在其回调内的任何异步函数完成之前很久就完成了。因此,您尝试在填充posts之前返回它。
async回调传递给.map()将返回一个promise数组。您可以在这些promise上使用Promise.all()来知道它们何时完成。一旦您这样做了,您还可以返回每个post对象,而不是使用更高级别的作用域/共享对象,从而使代码更加自包含。
我建议使用以下代码:

async function run(url) {
    try {
        console.log(url);
        const { data } = await axios(url);
        const $ = load(data);
        const posts = await Promise.all($(".thing.linkflair.link").map(async (i, e) => {
            const title = $(e)
                .find(".entry.unvoted .top-matter .title .title")
                .text();
            const user = $(e)
                .find(".entry.unvoted .top-matter .tagline .author")
                .text();
            const profileLink = `https://old.reddit.com/user/${user}`;
            const postLink = `https://old.reddit.com/${$(e).find("a").attr("href")}`;
            // const thumbail = $(e).find("a img").attr("src");
            const image = await getImage(postLink);
            // return a post object
            return {
                id: i + 1,
                title,
                postLink,
                image,
                user: { user, profileLink },
            };
        }));
        const nextPage = $(".next-button a").attr("href");
        if (nextPage) {
            const newPosts = await run(nextPage);
            // add these posts to the ones we already have
            posts.push(...newPosts);
        }
        return posts;
    } catch (error) {
        console.error(error);
    }
}

相关问题