如何使用promise在循环后获取数据
How to get data after loop using promise
我正在处理异步问题。我正在制作一个网络抓取器,在我抓取网络后,我需要将数据放入我的 MongoDB 数据库中。我需要将它发送到前端,但由于我有一个循环元素我不能把 res.json()
放在里面,因为它会报错(你只能在 res.json())
.
之后发送一次
我被困在这里了。我以前用过 promises,但这很令人困惑。
router.get('/scrape', (req, res) => {
request('http://www.nytimes.com', function test(error, response, html) {
const $ = cheerio.load(html);
// An empty array to save the data that we'll scrape
const results = [];
$('h2.story-heading, p.summary').each(function(i, element) {
const link = $(element)
.children()
.attr('href');
const title = $(element)
.children()
.text();
const summary = $(element)
.children()
.text();
const data = {
title: title,
link: link,
summary: summary,
};
articles
.create(data)
.then((resp) => results.push(resp))
// .then((resp) => Promise.resolve(results)) //
// .then((jsonDta ) => res.json(jsonData)) // error you can only give response once.
.catch((err) => reject(err));
});
console.log(results); // empty array
res.json(results)// empty
});
});
我的计划是:
- 抓取网站(循环元素)
- 然后保存到MongoDB(将数据压入数组)
- 然后在循环后传递给前端。
我需要将查询方法 create...
放在循环中,因为我需要每个数据都有一个 id。
使用 .map 函数 return 所有对 Promise.all 的承诺,然后 return 结果。
request('http://www.nytimes.com', function test(error, response, html) {
const $ = cheerio.load(html);
var summary = $('h2.story-heading, p.summary')
Promise.all(summary.map((i, element) =>{
const data = {
title: $(element).children().text(),
link: $(element).children().attr('href'),
summary: $(element).children().text(),
};
return articles
.create(data)
}).get())
.then((result)=>{
console.log(result);
res.json(result);
});
})
您可以将 $('h2.story-heading, p.summary')
中包含的元素映射到一个 promises 数组,然后与 Promise.all()
进行聚合,而不是尝试直接累加结果。您想要的结果将在 Promise.all(...).then(...)
.
前送达
router.get('/scrape', (req, res) => {
request('http://www.nytimes.com', function test(error, response, html) {
const $ = cheerio.load(html);
const promises = $('h2.story-heading, p.summary')
.get() // as in jQuery, .get() unwraps Cheerio and returns Array
.map(function(element) { // this is Array.prototype.map()
return articles.create({
'title': $(element).children().text(),
'link': $(element).children().attr('href'),
'summary': $(element).children().text()
})
.catch(err => { // catch so any one failure doesn't scupper the whole scrape.
return {}; // on failure of articles.create(), inject some kind of default object (or string or whatever).
});
});
// At this point, you have an array of promises, which need to be aggregated with Promise.all().
Promise.all(promises)
.then(results => { // Promise.all() should accept whatever promises are returned by articles.create().
console.log(results);
res.json(results);
});
});
});
如果你想让任何一个失败破坏整个刮擦,然后省略 catch()
并将 catch()
添加到 Promise.all().then()
链。
备注:
对于 .get()
(以及大多数其他方法),jQuery documentation is better than the Cheerio documentation(但要小心,因为 Cheerio 是 jQuery 的精简版)。
你根本不需要new Promise()
。 articles.create()
.
返回你需要的所有承诺
类似这样的东西可能有效(代码未测试)
router.get('/scrape', (req, res) => {
request('http://www.nytimes.com', function test(error, response, html) {
const $ = cheerio.load(html);
// An empty array to save the data that we'll scrape
const results = [];
$('h2.story-heading, p.summary').each(function(i, element) {
const link = $(element)
.children()
.attr('href');
const title = $(element)
.children()
.text();
const summary = $(element)
.children()
.text();
const data = {
title: title,
link: link,
summary: summary,
};
const articleCreate = articles.create(data);
results.push(articleCreate);
});
console.log(results); // this is array of promise functions.
Promise.all(results).then(allResults => {
res.json(allResults)
});
// or you could use array.reduce for sequantial resolve instead of Promise.all
});
});
我正在处理异步问题。我正在制作一个网络抓取器,在我抓取网络后,我需要将数据放入我的 MongoDB 数据库中。我需要将它发送到前端,但由于我有一个循环元素我不能把 res.json()
放在里面,因为它会报错(你只能在 res.json())
.
我被困在这里了。我以前用过 promises,但这很令人困惑。
router.get('/scrape', (req, res) => {
request('http://www.nytimes.com', function test(error, response, html) {
const $ = cheerio.load(html);
// An empty array to save the data that we'll scrape
const results = [];
$('h2.story-heading, p.summary').each(function(i, element) {
const link = $(element)
.children()
.attr('href');
const title = $(element)
.children()
.text();
const summary = $(element)
.children()
.text();
const data = {
title: title,
link: link,
summary: summary,
};
articles
.create(data)
.then((resp) => results.push(resp))
// .then((resp) => Promise.resolve(results)) //
// .then((jsonDta ) => res.json(jsonData)) // error you can only give response once.
.catch((err) => reject(err));
});
console.log(results); // empty array
res.json(results)// empty
});
});
我的计划是:
- 抓取网站(循环元素)
- 然后保存到MongoDB(将数据压入数组)
- 然后在循环后传递给前端。
我需要将查询方法 create...
放在循环中,因为我需要每个数据都有一个 id。
使用 .map 函数 return 所有对 Promise.all 的承诺,然后 return 结果。
request('http://www.nytimes.com', function test(error, response, html) {
const $ = cheerio.load(html);
var summary = $('h2.story-heading, p.summary')
Promise.all(summary.map((i, element) =>{
const data = {
title: $(element).children().text(),
link: $(element).children().attr('href'),
summary: $(element).children().text(),
};
return articles
.create(data)
}).get())
.then((result)=>{
console.log(result);
res.json(result);
});
})
您可以将 $('h2.story-heading, p.summary')
中包含的元素映射到一个 promises 数组,然后与 Promise.all()
进行聚合,而不是尝试直接累加结果。您想要的结果将在 Promise.all(...).then(...)
.
router.get('/scrape', (req, res) => {
request('http://www.nytimes.com', function test(error, response, html) {
const $ = cheerio.load(html);
const promises = $('h2.story-heading, p.summary')
.get() // as in jQuery, .get() unwraps Cheerio and returns Array
.map(function(element) { // this is Array.prototype.map()
return articles.create({
'title': $(element).children().text(),
'link': $(element).children().attr('href'),
'summary': $(element).children().text()
})
.catch(err => { // catch so any one failure doesn't scupper the whole scrape.
return {}; // on failure of articles.create(), inject some kind of default object (or string or whatever).
});
});
// At this point, you have an array of promises, which need to be aggregated with Promise.all().
Promise.all(promises)
.then(results => { // Promise.all() should accept whatever promises are returned by articles.create().
console.log(results);
res.json(results);
});
});
});
如果你想让任何一个失败破坏整个刮擦,然后省略 catch()
并将 catch()
添加到 Promise.all().then()
链。
备注:
对于
.get()
(以及大多数其他方法),jQuery documentation is better than the Cheerio documentation(但要小心,因为 Cheerio 是 jQuery 的精简版)。你根本不需要
new Promise()
。articles.create()
. 返回你需要的所有承诺
类似这样的东西可能有效(代码未测试)
router.get('/scrape', (req, res) => {
request('http://www.nytimes.com', function test(error, response, html) {
const $ = cheerio.load(html);
// An empty array to save the data that we'll scrape
const results = [];
$('h2.story-heading, p.summary').each(function(i, element) {
const link = $(element)
.children()
.attr('href');
const title = $(element)
.children()
.text();
const summary = $(element)
.children()
.text();
const data = {
title: title,
link: link,
summary: summary,
};
const articleCreate = articles.create(data);
results.push(articleCreate);
});
console.log(results); // this is array of promise functions.
Promise.all(results).then(allResults => {
res.json(allResults)
});
// or you could use array.reduce for sequantial resolve instead of Promise.all
});
});