Как получить данные после цикла, используя обещание
Привет, кто-нибудь может мне помочь с моей асинхронной проблемой. я делаю веб-скребок и после того, как я скребу сеть. мне нужно поместить данные в мою базу данных (mongodb) после их ввода. мне нужно отправить их в интерфейс. но так как у меня есть цикл элементов, я не могу поставить res.json()
внутри itll выдал ошибку (отправить можно только один раз после res,json())
я застрял здесь. Я раньше использовал обещания, но это сбивает с толку.
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...
внутри цикла, потому что мне нужны все данные, чтобы иметь идентификатор. благодарю вас.
3 ответа
Вместо того, чтобы пытаться накапливать результаты напрямую, вы можете отобразить элементы, содержащиеся в $('h2.story-heading, p.summary')
к массиву обещаний, а затем объединить с 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 лучше, чем документация Cheerio (но будьте осторожны, потому что 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
});
});
Используйте функцию.map, чтобы вернуть все обещания в Promise.all, а затем вернуть результаты.
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);
});
})