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 执行并启动您的异步函数时,它不会等待。
所以你的数组将永远是空的。
作为练习,我正在创建一个简单的 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 执行并启动您的异步函数时,它不会等待。
所以你的数组将永远是空的。