0

Can someone explain why the following does not work as a solution to the "juggling async" lesson in the learnyounode workshop?

FYI I have left my log lines in if that helps. I am struggling to see any fundamental differences between my solution and an answer I found online here: https://github.com/olizilla/nodeschooling/blob/master/learnyounode-answers/09-juggling-async.js

Thanks in advance!

var urlList = process.argv.slice(2, process.argv.length);
//console.log(urlList);
var urlResponseList = {};

for(var i=0; i < urlList.length; i++)
{
    urlResponseList[urlList[i]] = '';
}

var http = require('http');


console.log(urlList);

for(var i = 0; i < urlList.length; i++) {
    //console.log(i);

    var url = urlList[i];

    console.log("1 " + url);

    http.get(url, function (response) {
        console.log("2 " + url);
        console.log("3 " + i);

        response.setEncoding('utf8');

        response.on('data', function (data) {
            urlResponseList[url] = urlResponseList[url] + data;
        });

        response.on('end', function () {
            //console.log(stringResponse);
            //console.log(url);
          });
    });
}
console.log(urlResponseList);

for(var i=0; i < urlList.length; i++){
    console.log(urlResponseList[urlList[i]]);
}

I also have a question about a solution I found posted online here: https://github.com/olizilla/nodeschooling/blob/master/learnyounode-answers/09-juggling-async.js

urls.forEach(function (item, index) {
  http.get(item, function (req) {
    req.setEncoding('utf8')
    req.pipe(concat(function (res) {
      data[index] = res;
      responseCount++
      if (responseCount === urls.length) {
        console.log(data.join('\n'));
      }
    }))
  })

if http.get is async and can the "index" variable be trusted in the http.get callback even though it is being set outside of the callback (in the foreach loop)?

I just wanted to post the updated solution below. Thanks for all the help. My issue was I didn't fully understand how closures worked.

var urlList = process.argv.slice(2, process.argv.length);
//console.log(urlList);
var urlResponseList = [];

for(var i=0; i < urlList.length; i++)
{
    urlResponseList.push('');
}

var http = require('http');

var responseCount = 0;

//console.log(urlList);

urlList.forEach(function(item, index){
    //console.log(i);
    var url = urlList[index];

    //console.log("1 " + url);

    http.get(item, function (response) {
        //console.log("2 " + url);
        //console.log("3 " + i);

        response.setEncoding('utf8');

        response.on('data', function (data) {
            urlResponseList[index] = urlResponseList[index] + data;
        });

        response.on('end', function () {
            responseCount++;
            if(responseCount == urlList.length)
            {
                //console.log("help");
                console.log(urlResponseList.join('\n'));
            }
          });
    });
});

//console.log(urlResponseList);
user1870738
  • 503
  • 1
  • 8
  • 14

1 Answers1

0

http.get() returns its result asynchronously (e.g. sometime later) in the callback. Your code execution does not wait for that result - the rest of your code keeps running even though the response is not yet here.

Thus, all requests will be sent at once from your first for loop, then your second for loop will run and THEN sometime later, the responses will arrive and the callbacks will be called. Your responses are going to arrive async and thus will NOT be available at the end of the first for loop. So, your first console.log(urlResponseList); will be empty and the second for loop will have nothing to do.

Async responses MUST be processed inside the callback in which they are delivered or they must be stored somewhere until the last response is done and then all responses can be processed at that time.

If you don't understand the issues behind asynchronous responses, then read these two references:

How do I return the response from an asynchronous call?

Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference


You also have issues with local variables declared before the callback that will have changed before the callback is called.

Here's an example of how you solve the for loop issue: JavaScript closure inside loops – simple practical example

Community
  • 1
  • 1
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • I really appreciate the quick response. I was looking at the response here: https://github.com/olizilla/nodeschooling/blob/master/learnyounode-answers/09-juggling-async.js The only thing that I didnt understand about this solution are the following lines: http.get(item, function (req) { req.setEncoding('utf8') req.pipe(concat(function (res) { data[index] = res; responseCount++ if (responseCount === urls.length) { console.log(data.join('\n')); } })) }) – user1870738 Oct 14 '14 at 05:07
  • @user1870738 - was that a question? Your reference processes each response IN the callback which is what I suggested for you and is not what you are doing in your code. It also maintains a counter so it can know when all requests are done which is one possible option. – jfriend00 Oct 14 '14 at 05:09
  • @user1870738 - with the latest edit to your comment, you are now asking what seems like a new/different question to me. Please start a new question for that. – jfriend00 Oct 14 '14 at 05:10
  • Sorry I meant to ask the following: I have a question about a solution I found in the following link: https://github.com/olizilla/nodeschooling/blob/master/learnyounode-answers/09-juggling-async.js Can we trust the variable index to be correct if the callback can can executed at anytime even though index is set outside of the callback? data[index] = res; – user1870738 Oct 14 '14 at 05:16
  • Sorry for any confusion but my last question / comment is related to the posted solution I referred to in my original question. Are you able to answer that question? Thanks again! – user1870738 Oct 14 '14 at 05:23
  • @user1870738 - please put the exact code you are asking about into your question with the edit link and then ask a specific question about it in your original post. It's doing a bunch of things so please be more specific about what you're asking. – jfriend00 Oct 14 '14 at 05:26