Skip to content

Instantly share code, notes, and snippets.

@Spencer-Allen
Last active August 29, 2015 14:05
Show Gist options
  • Save Spencer-Allen/e662f3ec4e7428505e4b to your computer and use it in GitHub Desktop.
Save Spencer-Allen/e662f3ec4e7428505e4b to your computer and use it in GitHub Desktop.
LearnYouNode problem.
//THE EXERCISE:
//This problem is the same as the previous problem (HTTP COLLECT) in that you need to use http.get().
//However, this time you will be provided with three URLs as the first three command-line arguments.
//You must collect the complete content provided to you by each of the URLs and print it to the console (stdout).
//You don't need to print out the length, just the data as a String; one line per URL.
//The catch is that you must print them out in the same order as the URLs are provided to you as command-line arguments.
//MY ISSUE:
//This is problem #9 on LearnYouNode from nodeschool.io
//They've specifically requested I NOT use [async] for this.
//This program runs well, except for *one* issue.
//On line 47, there's a callback in the function aSyncMap
//if I put it inside of the forEach function, it returns data as required, but not in the right order.
//when outside of the forEach, it seems to not get the proper scope of the var "results"
//Any thoughts?
var http = require('http');
var bl = require('bl');
var urls = [];
process.argv.slice(2).forEach(function(item){
urls.push(item)
});
function getter(url, callback){
http.get(url, function(response) {
response.setEncoding('utf8');
response.pipe(bl(function(err, data){
if (err) {
return callback(err);
}
callback(data.toString());
}));
});
}
function aSyncMap(array, getter, callback){
var results = [];
var completed = array.length;
array.forEach(function (item, index){
getter(item, function(data){
results[index] = data;
completed -= 1;
if (completed === 0){
callback(results);
}
});
});
}
aSyncMap(urls, getter, function(results){
results.forEach(function(item, index){
console.log(item);
});
});
@andyburke
Copy link

function aSyncMap(array, getter, callback){
  var results = [];
  array.forEach(function (item, i){
    // the following line of code runs for each item in turn, but your anonymous function that will insert into results doesn't happen until the http response is done
   // in the meantime, the variable 'i' has been updated, so things may get inserted incorrectly
    getter(item, function(data){
      results.splice(i,0,data);
    });
  });

  // this line will execute before all getter() calls have completed (it may actually happen after, but that would be a lucky case
  // this callback should only happen once all results are in
  callback(results);
}

I won't give you the solution unless you ask, but what you need to think about is 'capturing' the index variable 'i' into a scope such that when your getter() method calls back with the results, you can make sure to put them at the expected index.

You can also think about only calling callback() once all getter() calls have come back: you might want to keep a count.

@tmarthal
Copy link

Search for 'count down latch' or 'conditional variable'.... or go full javascript and look up Promises.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment