0

How could I implement a .then promise, so once this function runs I have something inside of the array?

I can console.log the results into the function and I believe it returns the results correctly, however the res.json results will show an empty array. Which I assume is because it loads quicker than the function finishes.

const {grabArticles} = require('../controller/update.js');

// variables
const router = express.Router();


router.get('/new', (err, res) => {
  const results = [];
  const test = grabArticles(results)
  test.then((results) => {
    res.json(results);
  })
});

//different file
const request = require('request');
const cheerio = require('cheerio');

grabArticles = (results) => {
  // const results = [];
  request("https://fivethirtyeight.com/", function(error, response, html) {
    const $ = cheerio.load(html);
    for (x=1; x<4; x++) {
      // i is the current loop number, element=this is the current data requested
      $('#home-feature-' + x.toString()).each((i, element) => {
        const topic = $(element).children('.post-info').children('.topic').text().trim();
        const title = $(element).children('.post-info').children('.tease-meta').children('.tease-meta-content').children('h2.article-title.entry-title').text().trim();
        // console.log('topic: ' + topic + '\n' + 'title: ' + title);
        const newArticle = {
          topic: topic,
          title: title
        };
        results.push(newArticle);
      })
    }
    console.log('inside update.js' + results);
  });
  return results;
}
RandomC
  • 3
  • 6

2 Answers2

1

You need to return a Promise, which then resolves the results. The value of results will then be passed to your then callback as the first parameter.

Untested but it will look something like this:

//different file
const request = require('request');
const cheerio = require('cheerio');

grabArticles = (results) => {
  // const results = [];
  return new Promise(function(resolve) {
    request("https://fivethirtyeight.com/", function(error, response, html) {
      const $ = cheerio.load(html);
      for (x = 1; x < 4; x++) {
        // i is the current loop number, element=this is the current data requested
        $('#home-feature-' + x.toString()).each((i, element) => {
          const topic = $(element).children('.post-info').children('.topic').text().trim();
          const title = $(element).children('.post-info').children('.tease-meta').children('.tease-meta-content').children('h2.article-title.entry-title').text().trim();
          // console.log('topic: ' + topic + '\n' + 'title: ' + title);
          const newArticle = {
            topic: topic,
            title: title
          };
          results.push(newArticle);
        })
      }
      console.log('inside update.js' + results);
      
      //////////////////////////
      /// Resolve the promise here
      /// the then() will get triggered
      //////////////////////////
      resolve(results);
    });
  });
}

A very simplified version would look like this:

// This function returns a Promise
function doSomethingAysnc(){
    return new Promise(function(resolve){
        request('/my/url', function(data){
            // When we are staisfied with ending the promise
            // We resolve it so the calling function can then 
            // handle the rest
            return resolve(data);
        });
    });
}

// Here we will call our async function
// Once the promise resolves
// We get our data back for further usage
doSomethingAysnc().then(function(data){
    // We can the access the data here
    console.log(data);
});
Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338
  • Better put all those `cheerio` processing in a `then` callback where exceptions will be handled, and wrap only the `request` call itself in the `new Promise` – Bergi Nov 03 '17 at 03:28
0

Rewrite your grabArticles using Promise like this.

grabArticles = (results) => {
  return new Promise((resolve, reject) => {
    request("https://fivethirtyeight.com/", function(error, response, html) {
      const $ = cheerio.load(html);
      for (x=1; x<4; x++) {
        // i is the current loop number, element=this is the current data requested
        $('#home-feature-' + x.toString()).each((i, element) => {
          const topic = $(element).children('.post-info').children('.topic').text().trim();
          const title = $(element).children('.post-info').children('.tease-meta').children('.tease-meta-content').children('h2.article-title.entry-title').text().trim();
          // console.log('topic: ' + topic + '\n' + 'title: ' + title);
          const newArticle = {
            topic: topic,
            title: title
          };
          results.push(newArticle);
        })
      }
      console.log('inside update.js' + results);
      // return result using resolve, otherwise using reject(error) to reflect something wrong
      resolve(results);
    });
  });
}
Donghua Liu
  • 1,776
  • 2
  • 21
  • 30