0

I am using geocoder npm module to convert the address to lat,long. This API reads address from file google.csv using fast csv npm module after that result i.e addresses are passed to getLatLong function to convert to latitude and longitude respectively .Now when I pass latlongArray in getLatLong callback it goes empty.This is getting because of scope.Kindly suggest.

const geocoder   = require('geocoder');
const json2csv   = require('json2csv');
const fs         = require('fs');
const csv        = require('fast-csv'); 
var stream       = fs.createReadStream("google.csv");
var path         = './google.csv';
var async        = require('async');
var responseObj  = {};
var latlongArray = [];

var asyncArray   =[getCsvdata.bind(null, path, responseObj),
                   getLatLong.bind(null, responseObj)];
async.series(asyncArray ,function(err, result){
    if(err){
        console.log(err);
        return err;
    }   
     console.log(JSON.stringify(result));
})

function getCsvdata(path, responseObj, callback){
    var SuccessArray = [];
    var ErrorArray   = [];
    csv.fromPath(path)
        .on('data', function (data) {
            SuccessArray.push(data);
        })
        .on("error", function (data) {
            ErrorArray.push(data);
        })
        .on('end', function () {
            var ResultObject         = {Success: SuccessArray, ErrorList: ErrorArray};
            responseObj.adrressarray = ResultObject;
            callback(null, ResultObject);
        });
 }
function getLatLong(responseObj, callback){
    var responseArray = responseObj.adrressarray; 
    var geocodeArray  = responseArray.Success.slice(1);
    var geoLatLong   = geocodeArray.map(function(x) {
            var addressOfRow = x.toString();
            geocoder.geocode(addressOfRow, function (err, data) {
            if(err){
                return callback(err);
            }
            var latitude    = data.results[0].geometry.location.lat;
            var longitude   = data.results[0].geometry.location.lng;
            var address     = data.results[0].formatted_address;
            var obj         = [{"latitude":latitude,"longitude":longitude, "address":address}];
            latlongArray.push(obj);
        })
    }); 

    return callback(null, latlongArray);
}
2
  • That happens because your callback is fired before you code executed since you are using an asynchronous function's callback to populate that variable. Commented Jul 29, 2017 at 13:23
  • That is true @Salketer Commented Jul 29, 2017 at 13:25

2 Answers 2

1

You'll want to use async.parallel. Since you are calling multiple geocoder.geocode. Since it is asynchronous, your function returns a value before they have ended.

function getLatLong(responseObj, callback){
    var responseArray = responseObj.adrressarray; 
    var geocodeArray  = responseArray.Success.slice(1);
    var geoLatLongFunctions   = geocodeArray.map(function(x) {
        return function(cb){
            var addressOfRow = x.toString();
            geocoder.geocode(addressOfRow, function (err, data) {
                if(err){
                     cb(err);
                }
                var latitude    = data.results[0].geometry.location.lat;
                var longitude   = data.results[0].geometry.location.lng;
                var address     = data.results[0].formatted_address;
                var obj         = [{"latitude":latitude,"longitude":longitude, "address":address}];
                cb(null,obj);
            });
         };
    }); 
    async.parallel(geoLatLongFunctions,callback);
}

Here, what I've done is make your geocodeArray.map return a function instead. And used async.parallel to execute them. Once all of them has finished, the callback will be called containing the results of all executions.

Sign up to request clarification or add additional context in comments.

2 Comments

can you please explain how the getLatLong finally returned to async.series?@Salketer
See documentation on async.parallel: "Once the tasks have completed, the results are passed to the final callback as an array."
1

You are calling the callback too soon (synchronously), while the array is only populated later (asynchronously).

Make these changes:

function getLatLong(responseObj, callback){
    var latlongArray = []; // Define & initialise array here!
    var responseArray = responseObj.adrressarray; 
    var geocodeArray  = responseArray.Success.slice(1);
    geocodeArray.map(function(x) {
        var addressOfRow = x.toString();
        geocoder.geocode(addressOfRow, function (err, data) {
            if(err){
                return callback(err);
            }
            var latitude    = data.results[0].geometry.location.lat;
            var longitude   = data.results[0].geometry.location.lng;
            var address     = data.results[0].formatted_address;
            var obj         = [{"latitude":latitude,"longitude":longitude, "address":address}];
            latlongArray.push(obj);
            // Only call callback when array is complete
            if (latlongArray.length == geocodeArray.length) {
                callback(null, latlongArray);
            }
        })
    }); 
}

8 Comments

can you please explain how the getLatLong finally returned to async.series?@trincot in the above answer of @Salketer
I think here it is clear, right? I added a comment on the other answer.
As you said "Once the tasks have completed, the results are passed to the final callback as an array", but the tasks were of geocode and thier results are passed to async.parallel final callback , From this geocode function there is no callback(err ,result) so how it gets to async.series @trincot
The async.parallel implementation will capture the callbacks made by the geocode tasks, collect the data it gets from those, and then call the final callback with that data, which is captured in async.series.
Last doubt .Where is the call from final callback of async.parallell which is being Captured in async.series@trincot
|

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.