Arthur Frankel
Arthur Frankel

Reputation: 4705

Closures, loops, and promises

I've read several posts on the subject, but unfortunately struggling with my situation.

I am pulling some urls from an array of urls and then using those links to obtain (let's say) the title of the page from those subsites. At the end I want a list of original urls and an array of titles (from the sublinks). i.e., go into a site/domain, find some links, curl those links to find page titles.

Problem is that my titleArray just returns a Promise and not the actual data. I'm totally not getting closures right and promises. Code runs in node as is. I'm using personal sites in my real code, but substituted common sites to show an example.

const popsicle = require('popsicle');

var sites = ['http://www.google.com','http://www.cnn.com'];

// loop through my sites (here I'm just using google and cnn as a test
for(var i=0;i<sites.length;i++) {
  // call function to pull subsites and get titles from them
  var titleArray = processSites(sites[i]);

  console.log(sites[i] + ": " + titleArray);
}

// get request on site and then get subsites
function processSites(url) {
  return popsicle.get(url)
    .then(function(res) {
      var data = res.body;

      // let's assume I get another collection of URLs
      // that I pull from the main site
      var subUrls = ['http://www.yahoo.com','http://www.espn.com'];
      var titleArray = [];
      for(var j=0;j<subUrls.length;i=j++) {
        var title = processSubSites(subUrls[j])
        titleArray.push(title);
      }
      return titleArray;
    });
}

function processSubSites(url) {

  return popsicle.get(url)
    .then(function(res) {
      var data = res.body;
      // let's say I pull the title of the site somehow
      var title = "The Title for " + url;
      console.log(title);
      return title;
    });

}

The result after running this is:

http://www.google.com: [object Promise]
http://www.cnn.com: [object Promise]
The Title for http://www.espn.com
The Title for http://www.espn.com
The Title for http://www.yahoo.com
The Title for http://www.yahoo.com

whereas it should be:

http://www.google.com: ['The Title for http://www.yahoo.com', 'The Title for http://www.espn.com']
http://www.cnn.com: ['The Title for http://www.yahoo.com', 'The Title for http://www.espn.com']
...

Upvotes: 0

Views: 151

Answers (1)

shawon191
shawon191

Reputation: 1955

You cannot return normal data from inside a Promise. You need to return another Promise to make it chainable. To process multiple Promise objects in loop, you need to push them in an array and call Promise.all(array);

const popsicle = require('popsicle');

var sites = ['http://www.google.com','http://www.cnn.com'];

var titleArrayPromises = [];
// loop through my sites (here I'm just using google and cnn as a test
for(var i=0;i<sites.length;i++) {
  titleArrayPromises.push(processSites(sites[i]));
}

var titleArray = [];
Promise.all(titleArrayPromises).then(function (titleArrays) {
  for(var i=0; i<titleArrays.length; i++) {
    titleArray.concat(titleArrays[i])
  }
  // You now have all the titles from your site list in the titleArray
})

function processSites(url) {
  return popsicle.get(url)
    .then(function(res) {
      var data = res.body;

      // let's assume I get another collection of URLs
      // that I pull from the main site
      var subUrls = ['http://www.yahoo.com','http://www.espn.com'];
      var titlePromiseArray = [];
      for(var j=0;j<subUrls.length;j++) {
        titlePromiseArray.push(processSubSites(subUrls[j]));
      }
      return Promise.all(titlePromiseArray);
    });
}

function processSubSites(url) {
  return popsicle.get(url)
    .then(function(res) {
      var data = res.body;
      // let's say I pull the title of the site somehow
      var title = "The Title for " + url;
      return Promise.resolve(title);
    });  
}

Upvotes: 1

Related Questions