-1

I was trying to get a few infos into a variable by scraping and collecting with the request module. My guess is that I am unable to show the results in the temp_table variable because it is not executed in the correct timing, as the request method is asynchronous while console.log(temp_table) is not.

I thought about adding a callback to my code but I have no idea where to add it, giving the codebase below.

My interest is in populating the array temp_table with what comes out of the request function which is run as many times as the length of the places array.

----------------------------------------------

var request = require("request"),
cheerio = require("cheerio"),
fs = require("fs");

var places = [
    {
        'url' : 'http://www.ilmeteo.it/portale/meteo/previsioni.php?citta=Empoli&c=2635&gm=10&g=1&lang=ita',
        'city' : 'a town'}
   {
        'url' : 'http://www.ilmeteo.it/portale/meteo/previsioni.php?citta=Roma&c=2635&gm=10&g=1&lang=ita',
        'city' : 'another town'}
   {
        'url' : 'http://www.ilmeteo.it/portale/meteo/previsioni.php?citta=Firenze&c=2635&gm=10&g=1&lang=ita',
        'city' : 'another town'}
];

var temp_table = [];

luoghi.forEach(function(el){
    request(el.url, function (error, response, body) {
              if (!error) {
                var $ = cheerio.load(body);
                temp = $(".datatable .expa").html();
                var h = [], t = [], u = [];


                // temp contains the data from the website in html format, it is rewritten in each iteration

                var orario = $(".datatable .expa .ora").text().trim();

                    orario = orario.match(/.{1,2}/g);
                    for (i = 0; i < 3; i++){
                        h.push(orario[i]);
                    }

                var temperatura = $(".datatable .expa .col4 span").text().trim();


                    temperatura = temperatura.match(/\d+\.\d+/g);
                    ascii_code_temperatura = String.fromCharCode(176);
                    for (i = 0; i < 3; i++){
                        t.push(temperatura[i] + ascii_code_temperatura);
                    }

                var humidity = $(".datatable .expa .col10 span:first-child").text().trim();

                    humidity = humidity.match(/\d+\%/g);
                    for (i = 0; i < 3; i++){
                        u.push(humidity[i]);
                    }

                temp_table.push({
                    "city" : el.city,
                    "t1" : {
                        "ora" : h[0],
                        "temperatura" : t[0],
                        "humidity" : u[0]
                    },
                    "t2" : {
                        "ora" : h[1],
                        "temperatura" : t[1],
                        "humidity" : u[1]                       
                    },
                    "t3" : {
                        "ora" : h[2],
                        "temperatura" : t[2],
                        "humidity" : u[2]                       
                    }
                });
              } else {
                console.log("We’ve encountered an error: " + error);
              }

              //temp_table is readable here

        });
        //temp_table is empty here, probably because of callback
        console.log(temp_table)
        // THIS ONE UP HERE IS NOT READ, IT LOGS AN EMPTY ARRAY EACH TIME
}); // FOREACH END
       console.log(temp_table)
       // THIS ONE UP HERE IS NOT READ, IT LOGS NOTHING

Thanks in advance for the help.

Edit: marking it as a duplicate without actually helping me is not helpful at all. I did search for answers before posting the question and I didn't come up with one, hence the question.

  • question. what you want is to get `temp_table` which is fully filled by the foreach? – Beginner Dec 09 '16 at 15:40
  • Yes, each time the foreach is run it should fill a temp_table[index] with information, so having 3 towns in the example, it should be a table with 3 values inside of it at the end of the cycle and it should be reachable from the outside of the request scope. – 404answernotfound Dec 09 '16 at 15:42
  • Instead of using forEach you can use a function each of module 'async', here is a documentation: http://caolan.github.io/async/docs.html#each – sergiy.dragunov Dec 09 '16 at 15:51
  • "Edit: marking it as a duplicate without actually helping me is not helpful at all. I did search for answers before posting the question and I didn't come up with one, hence the question." — You didn't come up with one, but we did. That's helpful. Look at the duplicate. – Quentin Dec 09 '16 at 15:55
  • In addition to Quentin's comment, if your question is marked duplicate, but you believe it is not, you should describe how your question or problem is substantively different from the one being solved by the answers in the duplicate target provided by the expert in JavaScript that marked it as a duplicate in the first place. – TylerH Dec 09 '16 at 20:52

1 Answers1

0

As you stated above in your question you are right Since you're using asynchronous function you must use a callback function

Solution First: wrap your foreach inside a function

function myfunction(callback) {

declare a variable which will increment every time a callback is finish

    var itemsProcessed  = 0;

    luoghi.forEach(function(el){
        request(el.url, function (error, response, body) {

        // other code

Increment it by 1 after a callback is done

        itemsProcessed++;       

Check if your itemsProcessed value is now equal to the total count of your array which means your foreach is now finish

        if (itemsProcessed == luoghi.length) {

Then just call your passed callback after that and just passed also the temp_table

            return callback(temp_table);
        }

    })
}

then to call this function an get it's right value of temp_table

myfunction(function(temp_table) { // your callback
    console.log(temp_table);
})

So your code would be like this

var request = require("request"),
cheerio = require("cheerio"),
fs = require("fs");

var places = [
    {
        'url' : 'http://www.ilmeteo.it/portale/meteo/previsioni.php?citta=Empoli&c=2635&gm=10&g=1&lang=ita',
        'city' : 'a town'}
   {
        'url' : 'http://www.ilmeteo.it/portale/meteo/previsioni.php?citta=Roma&c=2635&gm=10&g=1&lang=ita',
        'city' : 'another town'}
   {
        'url' : 'http://www.ilmeteo.it/portale/meteo/previsioni.php?citta=Firenze&c=2635&gm=10&g=1&lang=ita',
        'city' : 'another town'}
];

var temp_table = [];

function get_temp_table(callback) {

    var itemsProcessed  = 0;
    luoghi.forEach(function(el){
        request(el.url, function (error, response, body) {
                  if (!error) {
                    var $ = cheerio.load(body);
                    temp = $(".datatable .expa").html();
                    var h = [], t = [], u = [];


                    // temp contains the data from the website in html format, it is rewritten in each iteration

                    var orario = $(".datatable .expa .ora").text().trim();

                        orario = orario.match(/.{1,2}/g);
                        for (i = 0; i < 3; i++){
                            h.push(orario[i]);
                        }

                    var temperatura = $(".datatable .expa .col4 span").text().trim();


                        temperatura = temperatura.match(/\d+\.\d+/g);
                        ascii_code_temperatura = String.fromCharCode(176);
                        for (i = 0; i < 3; i++){
                            t.push(temperatura[i] + ascii_code_temperatura);
                        }

                    var humidity = $(".datatable .expa .col10 span:first-child").text().trim();

                        humidity = humidity.match(/\d+\%/g);
                        for (i = 0; i < 3; i++){
                            u.push(humidity[i]);
                        }

                    temp_table.push({
                        "city" : el.city,
                        "t1" : {
                            "ora" : h[0],
                            "temperatura" : t[0],
                            "humidity" : u[0]
                        },
                        "t2" : {
                            "ora" : h[1],
                            "temperatura" : t[1],
                            "humidity" : u[1]                       
                        },
                        "t3" : {
                            "ora" : h[2],
                            "temperatura" : t[2],
                            "humidity" : u[2]                       
                        }
                    });
                  } else {
                    console.log("We’ve encountered an error: " + error);
                  }

                  //temp_table is readable here
            itemsProcessed++;
            if (itemsProcessed == luoghi.length) {
                return callback(temp_table);
            }
        });
    }); // FOREACH END
}


get_temp_table(function(temp_table) {
    console.log(temp_table); // this should have a result now
});
Beginner
  • 4,118
  • 3
  • 17
  • 26