0

I have a function:

var third = function(classes){
  for (var i = 0; i <= (classes.length-1); i++) {
       var Myurl = classes[i];

       return function(Myurl){
          request(Myurl,  function(err, resp, body) { 
             if (!err && resp.statusCode == 200) {
                var $ = cheerio.load(body);
                $("#item_details dl").each(function() {
                   var Values = [];
                   var New = [];

                   Values=$(this).find("dd strong").text();

                   New = Values.replace(/[\n\t\r]/g,"");
                   AllLinks.push(New);
                });

                console.log(AllLinks);
             };
          })
       }(MyUrl);

  };
};

The problem is when I do the above I only get the result of first loop element (i=0) in the console.log(AllLinks). How do I properly loop in node? I am new to node so any comments are much appreciated!

EDIT: If I define AllLinks in request then it seems to work, but not in correct order...

var third = function(classes){
      for (var i = 0; i <= (classes.length-1); i++) {
           var Myurl = classes[i];

            (function(Myurl){
              request(Myurl,  function(err, resp, body) { 
                 if (!err && resp.statusCode == 200) {
                    var $ = cheerio.load(body);
                    AllLinks=[];
                    $("#item_details dl").each(function() {
                       var Values = [];
                       var New = [];

                       Values=$(this).find("dd strong").text();

                       New = Values.replace(/[\n\t\r]/g,"");
                       AllLinks.push(New);
                    });

                    console.log(AllLinks);
                 }(Myurl);
              })
           };

      };
    };
11
  • async library npmjs.com/package/async Commented May 26, 2015 at 10:01
  • @CallumLinington Thanks, I am a node beginner, so you maybe can provide an example about how the above function should be changed? best regards Commented May 26, 2015 at 10:02
  • Why do you want to return call result return function(Myurl){...}(MyUrl);? In certain scenarios it might be enough. Otherwise you might want to try promises or async library Commented May 26, 2015 at 10:03
  • @Igor how do you mean? Commented May 26, 2015 at 10:06
  • I'm not sure how you implement request but if you drop 'return' you'll most likely be able to call all your urls from classes. If you want to wait for all calls to succeed async.js sounds like your choice. Commented May 26, 2015 at 10:09

3 Answers 3

4

The major problem (apart from 'return') is that assuming request performs asyncronous operation your function returns when request is not completed and thus log contains no update.

You have two strategies in general:

  1. call your code without 'return' as in the example above. This case all your requests will be eventually done but you have no control over when. It works well when you don't need them all to proceed, e.g. process AllLinks afterwards
  2. Use any technology that supports waiting until all your calls are completed (async.js or promises). For example here Simplest way to wait some asynchronous tasks complete, in Javascript?

Thus you need:

function appendResultToItems(url, callback) {
 request(url,  function(err, resp, body) { 
   if (!err && resp.statusCode == 200) {
     var $ = cheerio.load(body);
     $("#item_details dl").each(function() {
       var Values = [];
       var New = [];

       Values=$(this).find("dd strong").text();

       New = Values.replace(/[\n\t\r]/g,"");
       AllLinks.push({result:New, url: url});
       callback();
     });
 });
}

var calls = [];

classes.forEach(function(Myurl){
  calls.push(function(callback) {
    appendResultToItems(Myurl, callback);
  });
});

async.parallel(calls, function() {
  console.log(AllLinks);
});
Sign up to request clarification or add additional context in comments.

8 Comments

Great answer, please see my edit. Is that what you mean, the edit code works but AllLinks are not in correct order...
You can't have them in order this case. What you can do is to write results by url or classes index and then reorder them
Btw, what is "callback" function in the example above?
It's the most simple way of notifying the function has completed. Normally it is called with result and/or error as parameters
So the callback is asyncsCallback you mean?
|
1

Use async.js#eachSeries to apply an asynchronous function to each element of a collection

2 Comments

thanks, but do you have an example of how the above function should be changed? I am a node beginner...
@user1665355 on async.js you will find more than examples
1

Your problem is you are using return within the loop. If you simply use an IIFE

var third = function(classes){
  for (var i = 0; i <= (classes.length-1); i++) {
       var Myurl = classes[i];

       (function(Myurl){
          request(Myurl,  function(err, resp, body) { 
             if (!err && resp.statusCode == 200) {
                var $ = cheerio.load(body);
                $("#item_details dl").each(function() {
                   var Values = [];
                   var New = [];

                   Values=$(this).find("dd strong").text();

                   New = Values.replace(/[\n\t\r]/g,"");
                   AllLinks.push(New);
                });

                console.log(AllLinks);
             };
          })
       })(MyUrl);

  };
};

AllLinks will be correctly generated.

1 Comment

that does not give the correct results unfortunately! AllLinks are not correct...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.