2

So I have read a lot of the different answers about asynchronous functions on here but I think I am over thinking my problem, or I have been staring at it just to long and I cant figure it out. So your help is greatly appreciated.

So I am parsing a csv file and then trying to get the lat/long through another api. but I cant access the lat/lng outside of the function. below is my code I have commented it to the best of my ability please let me know if there are any questions or a much better way to do this.

Thanks,

var location = [] 
function run() {
    http.get(url, function(res) {
        if(res.statusCode === 200) {
            res.pipe(parse(function(err, data) {
                for(i = 1; i < data.length; i++) {
                    var info = data[i];
                    passLoc = info[6].replace('block ', '')
                    passLoc = passLoc.replace(/ /g, "+")
                    getLoc(passLoc, function(loc) {
                        location.push(loc);
                        //If I console.log(location) here I get all the info I want but.....it is printed 100 times becuase it is printed for each i in data.length
                    })
                }
                console.log(location) // loging this here gives me an empty array           
            }))
        }else {
            console.error('The address is unavailable. (%d)', res.statusCode);
        }
    })
}
function getLoc(x, callback) {
    var url = "http://geodata.alleghenycounty.us/arcgis/rest/services/Geocoders/EAMS_Composite_Loc/GeocodeServer/findAddressCandidates?Street=" + x + "&City=Pittsburgh&State=PA&ZIP=&SingleLine=&outFields=&outSR=4326&searchExtent=&f=pjson";
    http.get(url, function(res) {
        var data = '';
        res.on('data', function(chunk) {
            data += chunk;
        });
        res.on('end', function() {
            var d = JSON.parse(data);
            var obj = d.candidates;
            if(obj != '') {
                var loc = obj[0].location
                    var lat = loc.x
                    var lng = loc.y
                    var location = [lat, lng];
                callback(location)
            } else {
                callback(x);
            }
        });
        res.on('error', function(err) {
            callback("error!")
        });
    });
}
10
  • Please show only the relevant piece of code Commented Mar 1, 2015 at 14:21
  • took out the one function that isnt used hopefully that helps Commented Mar 1, 2015 at 14:23
  • Not just that. Most of your application logic and the comments related to that, may not be related to the actual problem. Please remove them also. Because, most people may not like to read pages of code to find the problem for you. Commented Mar 1, 2015 at 14:24
  • first time I am getting comments about to much code lol but ok trimmed it down hopefully that helps just kept the comment regarding what the error i get is Commented Mar 1, 2015 at 14:29
  • @thefourtheye any thoughts on the issue? Commented Mar 1, 2015 at 14:41

1 Answer 1

3

Your code tries to synchronously consume asynchronous data -- you're synchronously trying to access the results (location) before any of the asynchronous operations have finished.

As you have multiple async operations running in parallel, you can make use of async.parallel to aid in controlling the asynchronous flow:

var async = require('async');

function run() {
    http.get(url, function(res) {
        if(res.statusCode === 200) {
            res.pipe(parse(function(err, data) {
                // array of async tasks to execute
                var tasks = [];

                data.slice(1).forEach(function(info) {
                    var passLoc = info[6].replace('block ', '').replace(/ /g, '+');

                    // push an async operation to the `tasks` array
                    tasks.push(function(cb) {
                        getLoc(passLoc, function(loc) {
                            cb(null, loc);
                        });
                    });
                });

                // run all async tasks in parallel
                async.parallel(tasks, function(err, locations) {
                    // consume data when all async tasks are finished
                    console.log(locations);
                });
            }));
        }else {
            console.error('The address is unavailable. (%d)', res.statusCode);
        }
    });
}

Also, for loops don't create a scope, so I've swapped it by a forEach in order to scope the info and passLoc variables inside each iteration.

Here's a slightly more condensed version using ES5's Array#map:

var async = require('async');

function run() {
    http.get(url, function(res) {
        if(res.statusCode === 200) {
            res.pipe(parse(function(err, data) {
                async.parallel(
                    // map data items to async tasks
                    data.slice(1).map(function(info) {
                        return function(cb) {
                            var passLoc = info[6].replace('block ', '').replace(/ /g, '+');
                            getLoc(passLoc, function(loc) {
                                cb(null, loc);
                            });
                        };
                    }),
                    function(err, locations) {
                        // consume data when all async tasks are finished
                        console.log(locations);
                    }
                );
            }));
        } else {
            console.error('The address is unavailable. (%d)', res.statusCode);
        }
    });
}
Sign up to request clarification or add additional context in comments.

3 Comments

perfect thank you. also I didnt know about the difference between for and forEach. what do you mean by 'scope the info and passLoc'
I meant that, since for loops don't create a scope, all the functions ("tasks") created inside each iteration would reference the same info variable and end up with this problem: JavaScript closure inside loops
forEach, in the other hand, takes a function callback which is executed immediately (synchronously) for each iteration. As the function callback is executed for each iteration, the function's parameters and variable declarations are scoped inside each iteration, and this solves the issue more cleanly than the aforementioned question's accepted answer.

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.