Node.js API 中的异步函数未按预期工作

Asynchronous function in Node.js API not working as intended

作为练习,我正在创建一个简单的 API,它允许用户提供搜索词以检索指向资源集合中适当新闻文章的链接。相关函数及使用该函数的路由处理器如下:

function GetArticles(searchTerm) {

    const articles = [];

    //Loop through each resource
    resources.forEach(async resource => {

        const result = await axios.get(resource.address);

        const html = result.data;

        //Use Cheerio: load the html document and create Cheerio selector/API
        const $ = cheerio.load(html);

        //Filter html to retrieve appropriate links 
        $(`a:contains(${searchTerm})`, html).each((i, el) => {

            const title = $(el).text();

            let url = $(el).attr('href');

            articles.push(
                {
                    title: title,
                    url: url,
                    source: resource.name
                }
            );
        })
    })
    return articles; //Empty array is returned
}

以及使用函数的路由处理器:

app.get('/news/:searchTerm', async (req, res) => {
    const searchTerm = req.params.searchTerm;
    const articles = await GetArticles(searchTerm);
    res.json(articles);
})

我遇到的问题是返回的“articles”数组是空的。但是,如果我不是像 GetArticles 开头所评论的那样“遍历每个资源”,而是仅对单个“资源”执行主要逻辑,则“articles”将与请求的数据一起返回并且不为空。换句话说,如果函数如下:

async function GetArticles(searchTerm) {

    const articles = [];

    const result = await axios.get(resources[0].address);

    const html = result.data;

    const $ = cheerio.load(html);

    $(`a:contains(${searchTerm})`, html).each((i, el) => {

        const title = $(el).text();

        let url = $(el).attr('href');

        articles.push(
            {
                title: title,
                url: url,
                source: resources[0].name
            }
        );
    })

    return articles; //Populated array
}

然后“文章”不为空,正如预期的那样。

我确信这与我处理代码的异步性质的方式有关。我已经尝试刷新我对 JS 异步编程的了解,但我仍然无法完全修复该功能。显然,“articles”数组是在填充之前返回的,但是如何返回?

有人可以帮助解释为什么我的 GetArticles 函数适用于单个“资源”,但在遍历“资源”数组时却不行吗?

试试这个

function GetArticles(searchTerm) {

    return Promise.all(resources.map(resource => axios.get(resource.address))
     .then(responses => responses.flatMap(result => {

        const html = result.data;

        //Use Cheerio: load the html document and create Cheerio selector/API
        const $ = cheerio.load(html);
        let articles = []
        //Filter html to retrieve appropriate links 
        $(`a:contains(${searchTerm})`, html).each((i, el) => {

            const title = $(el).text();

            let url = $(el).attr('href');

            articles.push(
                {
                    title: title,
                    url: url,
                    source: resource.name
                }
            );
        })
        return articles;
    }))
    
}


你的实现中的问题就在这里 resources.forEach(async resource...

您已经定义了您的异步函数,但是当 result.foreach 执行并启动您的异步函数时,它不会等待。

所以你的数组将永远是空的。