1

I use request to read a website then parseString to convert and later save as json. The problem is saving. Looks like "for loop" keeps looping and when is saving the information uses the last info from var cta to assign to information. I have try asyn await but it didnt work. thanks in advance.

var fs      = require('fs');
var request = require('request');
var parseString = require('xml2js').parseString;

var json = {} ;

var cta = [
  {
    "_id": 1,
    "name": "PRWeb",
    "feedtype": "Misc",
    "feedaddress": "https://www.prweb.com/rss2/daily.xml",
    "status": true
  },
  {
    "_id": 2,
    "name": "Business Wire",
    "feedtype": "Industrie",
    "feedaddress": "https://feed.businesswire.com/rss/home/?rss=G1QFDERJXkJeGVtRVQ==",
    "status": false
  },
  {
    "_id": 3,
    "name": "News Wire",
    "feedtype": "Daily News",
    "feedaddress": "https://www.newswire.com/newsroom/rss/custom/all-press-releases",
    "status": true
  }
];

for (var i = 0; i < cta.length; i++) { 

  function getDatos(url, callback) {
      request(url, function(error, response, data){
          callback(error, response, data);
      });
  }

  if (cta[i].status === true) {
      console.log("cta: " + cta[i].feedaddress);

      agrabar = cta[i];
      console.log("agrabar:  " + agrabar.feedaddress);
      getDatos(agrabar.feedaddress, function(error, response, data){

           parseString(data, {explicitArray: false}, function (err, result) {
              if (err) {
                  return console.log('unable to parse XML');
              }

              json = {rssfeeder: agrabar, feed: result.rss.channel.item};
              console.log(json);
              fs.appendFile ("output.json", JSON.stringify(json, null, 4), function(err) {
              if (err) throw err;
              console.log('complete');
              });
          });
       });
  }

}
console.log('DONE!!!')
  • Possible duplicate of [JavaScript closure inside loops – simple practical example](https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Patrick Hund Dec 26 '18 at 21:14
  • Check out the duplicate link, this is quite a common mistake – Patrick Hund Dec 26 '18 at 21:15

1 Answers1

0

You seem to be mixing asynchronous code with synchronous code. It'd be great if you read more about how (and in what order) callbacks are handled in Javascript.

Example : Your final line of code console.log('DONE!!!') should actually be printed at the last when everything has finished, but when you'll run it, you'll be surprised that it's actually the first line to be printed to console. This is because the function getDatos is an asynchronous function, meaning that it will execute at some later point in time. Your for loop executes synchronously meaning that getDatos will be called thrice in the correct order, but owing to function closure in JS and asynchronicity, getDatos will be called after your final console.log has been done.

Furthermore, it's a good practice to use async await and Promises in modern JS, since it makes reading the code much more easier. I have modified your code to do what you intend to do and here it is. Hope it helps!

var fs      = require('fs');
var request = require('request');
var parseString = require('xml2js').parseString;

var cta = [
    {
        "_id": 1,
        "name": "PRWeb",
        "feedtype": "Misc",
        "feedaddress": "https://www.prweb.com/rss2/daily.xml",
        "status": true
    },
    {
        "_id": 2,
        "name": "Business Wire",
        "feedtype": "Industrie",
        "feedaddress": "https://feed.businesswire.com/rss/home/?rss=G1QFDERJXkJeGVtRVQ==",
        "status": false
    },
    {
        "_id": 3,
        "name": "News Wire",
        "feedtype": "Daily News",
        "feedaddress": "https://www.newswire.com/newsroom/rss/custom/all-press-releases",
        "status": true
    }
];

function getDatos(cta_object) {
    if (cta_object.status === false){
        return new Promise((resolve, reject) => resolve(false));
    }
    else {
        return new Promise((resolve, reject) => {
            request(cta_object.feedaddress, (err, response, data) => {
                if (err) reject(err);
                else resolve(data);
            })
        })
            .then((data) => {
                return new Promise((resolve, reject) => {
                    parseString(data, {explicitArray: false}, (err, result) => {
                        if (err) {
                            console.error("Unable to parse XML!");
                            return reject(err);
                        }
                        else return resolve(result);
                    });
                })
            })
            .then((result) => {
                console.log(result);
                return {
                    'rssfeeder': cta_object,
                    'feed': result.rss.channel.item
                };
            })
            .then((json) => {
                return new Promise((resolve, reject) => {
                    fs.appendFile ("output.json", JSON.stringify(json, null, 4), function(err) {
                        if (err) reject(err) ;
                        console.log("complete!");
                        resolve(true);
                    });
                })
            })
            .catch((err) => {
                throw(err);
            })
    }
};

Promise.all(cta.map((cta_obj) => getDatos(cta_obj)))
    .then(() => console.log('DONE!!!'))
    .catch((err) => {
        throw err;
    })
Mayank Sharma
  • 160
  • 3
  • 9