如何使用promise

时间:2018-08-19 19:14:20

标签: node.js asynchronous promise es6-promise scrape

您好,有人可以帮助我解决我的异步问题。即时通讯制作一个网页抓取工具,然后我抓取网页。将数据放入后,我需要将数据放入数据库(mongodb)中。我需要将其发送到前端。但由于我有一个循环,因此无法将res.json()放入其中,因此会出错(您只能在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...放入循环内,因为我需要每个数据都具有一个ID。谢谢。

3 个答案:

答案 0 :(得分:1)

您可以将public/中包含的元素映射到一个promise数组,而不是直接累加结果,然后与$('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()链中。

注意:

  1. 对于Promise.all().then()(和大多数其他方法)来说,jQuery documentationCheerio documentation更好(但请注意,因为Cheerio是jQuery的精简版本)。

  2. 您根本不需要.get()new Promise()返回了您需要的所有诺言。

答案 1 :(得分:0)

使用.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);
        });
    })

答案 2 :(得分:0)

类似的事情可能会起作用(代码未经测试)

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
  });
});