node.js - 如何使用 Promise 循环后获取数据

标签 node.js asynchronous promise es6-promise scrape

我正在解决异步问题。我正在制作一个网络抓取器,在抓取网络后,我需要将数据放入我的 MongoDB 数据库中。我需要将其发送到前端,但由于我有一个循环元素,所以我不能将 res.json() 放入其中,因为它会出错(在 res.json() 之后只能发送一次)

我被困在这里了。我以前使用过 Promise,但这很令人困惑。

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。

最佳答案

您可以映射 $('h2.story-heading, p.summary') 中包含的元素,而不是尝试直接累积结果。到一组 promise ,然后与 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()链。

注释:

  1. 对于 .get() (以及大多数其他方法),jQuery documentationCheerio documentation 更好(但要小心,因为 Cheerio 是 jQuery 的精益版本)。

  2. 您在任何时候都不需要new Promise() 。您需要的所有 promise 均由articles.create()返回.

关于node.js - 如何使用 Promise 循环后获取数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51921011/

相关文章:

node.js - 将 csv 文件上传到 Web api 时出现 502 错误

javascript - 将一组重叠的时间段合并到新的时间段中

javascript - 将javascript对象写入 Node 中的文件

C# .Net 套接字缓冲区理解

javascript - 如何判断请求/ promise 是否需要超过 5 秒才能完成,Angular JS

http - Angular2 中 Http 的 Promise 与 Observable?

python - 如何使用posix消息队列在 Node 和python之间进行IPC?

java - 有什么方法可以自动创建 Mongo 编解码器吗?

javascript - 如何确保所有使用 redux 的 promise 的正确顺序?

php - 使用 Guzzle 6 创建异步 json 请求池以发送到 API 端点的正确方法是什么?