-2

I'm newer in javascript programming and i'm trying to understand async process. I've started a project and i would to know how to execute the code below as sync. I saw a lot of tutorials but, most of them are so superficial...

The code is simple, its a call to google maps api that pass an adress and return the latitude and longitude. After that, it should call server passing lat lng through url and return all locations near by the location specified.

Client:

$scope.findLocations = function () {

    var dist = 0.1;

    //execute this
    getLatLong();

    //before this
    $http.get('/api/locations/findByLocation/'+$scope.form.lng+'/'+$scope.form.lat+'/'+dist)
    .success(function(data) {
        $scope.locations = data;
        $scope.form = {};
        console.log("locations: ", data);
    })
    .error(function(data) {
        console.log('Error: ' + data);
    });


};


var getLatLong = function() {

    var geo = new google.maps.Geocoder;

    var address = $scope.form.adress;

    console.log(address);

    geo.geocode({'address':address},function(results, status){
        if (status == google.maps.GeocoderStatus.OK) {
            console.log("Status geocoder OK");
            $scope.form.lat = results[0].geometry.location.lat();
            $scope.form.lng = results[0].geometry.location.lng();

            var latlng = new google.maps.LatLng($scope.form.lat,$scope.form.lng);

            var mapProp = {
                    center:latlng,
                    zoom:18,
                    mapTypeId:google.maps.MapTypeId.ROADMAP,
                    mapTypeControl: false
            };

            var map=new google.maps.Map(document.getElementById("map"),mapProp);
            var marker = new google.maps.Marker({
                    position: latlng,
                    map: map,
                    title:name
            });

            } else {
            alert(status);
        }

      });

};

Server:

router.get('/api/locations/findByLocation/:lng/:lat/:dist', function(req, res){

var coords = [];
coords[0] = req.params.lng;
coords[1] = req.params.lat;

Location.find({
    loc: {
        $near: coords,
        $maxDistance: req.params.dist
    }
}).limit(30).exec(function(err, locations){

    if(err){
        res.json(err);
        console.log(err);
    }

    res.json(locations);
});

});
Yanis-git
  • 7,737
  • 3
  • 24
  • 41
Denys Wylliam
  • 129
  • 2
  • 12
  • 1
    What exactly is your question? The body of your question should contain a clear question. You can't run an asynchronous operation as synchronous. Simply cannot be done in Javascript. You return asynchronous values via callback or promise as explained here [How do I return the response from an asynchronous call](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call/14220323#14220323) – jfriend00 Apr 21 '18 at 18:03

4 Answers4

1

Use JS Promise for this

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

$scope.findLocations = function() {

    var dist = 0.1;

    //execute this
    getLatLong().then(function(resolve) {
        //before this
        $http.get('/api/locations/findByLocation/' + $scope.form.lng + '/' + $scope.form.lat + '/' + dist)
            .success(function(data) {
                $scope.locations = data;
                $scope.form = {};
                console.log("locations: ", data);
            })
            .error(function(data) {
                console.log('Error: ' + data);
            });
    }, function(error) {
        alert("You got some error!");
    });

};



var getLatLong = function() {

    var geo = new google.maps.Geocoder;

    var address = $scope.form.adress;

    console.log(address);

    return new Promise(function(resolve, reject) {

        geo.geocode({
            'address': address
        }, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                console.log("Status geocoder OK");
                $scope.form.lat = results[0].geometry.location.lat();
                $scope.form.lng = results[0].geometry.location.lng();

                var latlng = new google.maps.LatLng($scope.form.lat, $scope.form.lng);

                var mapProp = {
                    center: latlng,
                    zoom: 18,
                    mapTypeId: google.maps.MapTypeId.ROADMAP,
                    mapTypeControl: false
                };

                var map = new google.maps.Map(document.getElementById("map"), mapProp);
                var marker = new google.maps.Marker({
                    position: latlng,
                    map: map,
                    title: name
                });

                resolve(200);
            } else {
                reject(status);
            }

        });
    });
};
Nishant Dixit
  • 5,388
  • 5
  • 17
  • 29
  • I think It is good for down voters to left some comment so I can realize my mistake Thanks. – Nishant Dixit Apr 21 '18 at 18:13
  • You implementation is nice and feet exactly with actual issue, don't understand why as well. Have just finish to write my sample couple of minutes after you and i have same approch to solve this issue. – Yanis-git Apr 21 '18 at 18:13
  • 1
    Didn't downvote, but I think you got downwoted because promises don't make your asynchronous code run synchronously. – dark_ruby Apr 21 '18 at 18:17
  • @dark_ruby There is nothing in Javascript which allow you to run async code in sync way except async/await but I not mentioned this above because It has lack of support in some old browser that is why I provide example with Promise which works with almost all browsers as compare to async/await. – Nishant Dixit Apr 21 '18 at 18:25
  • @NishantDixit yes I know. You asked why downvote, I gave you explanation. In fact even async/await doesn't make your code run synchronously, it only makes it look synchronous. – dark_ruby Apr 21 '18 at 19:48
  • Thanks for the link! i've applied promise here and it works like a charm! – Denys Wylliam Apr 21 '18 at 21:45
1

you should check how Promise work in javascript. here example :

var getLastLong = function() {
    return $q(function(resolve, reject) {

        var geo = new google.maps.Geocoder;

        var address = $scope.form.adress;

        console.log(address);

        geo.geocode({ 'address': address }, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                console.log("Status geocoder OK");
                $scope.form.lat = results[0].geometry.location.lat();
                $scope.form.lng = results[0].geometry.location.lng();

                var latlng = new google.maps.LatLng($scope.form.lat, $scope.form.lng);

                var mapProp = {
                    center: latlng,
                    zoom: 18,
                    mapTypeId: google.maps.MapTypeId.ROADMAP,
                    mapTypeControl: false
                };

                var map = new google.maps.Map(document.getElementById("map"), mapProp);
                var marker = new google.maps.Marker({
                    position: latlng,
                    map: map,
                    title: name
                });
                // say success with marker payload.
                resolve(marker);

            } else {
                // Say error with marker payload.
                reject(status);
            }
        });
    });
}

$scope.findLocations = function () {

    var dist = 0.1;
    getLatLong()
    .then(function(marker) {
        // Here you receive marker defer by promise, this code will be execute when "resolve" is call on your getLatLong() method
        $http.get('/api/locations/findByLocation/'+$scope.form.lng+'/'+$scope.form.lat+'/'+dist)
        .success(function(data) {
            $scope.locations = data;
            $scope.form = {};
            console.log("locations: ", data);
        })
        .error(function(data) {
            console.log('Error: ' + data);
        });

    })
    .catch(function(error) {
        console.log(error)
    });
};

Official promise api

angular 1 implementation of promise

Yanis-git
  • 7,737
  • 3
  • 24
  • 41
1

The way I prefer to deal with "this" then "this" then "that" chains in javascript is by using promises. It's a bit of a learning curve, but makes for simple maintainable code when dealing with async api calls. Start by including the $q dependency in your angular ?service? (it's unclear from the code posted from inside what angular component your calls are being made).

This is how it would look in your example:

 getLatLong()
 .then(function(longLat) {
      // process answer here
      $http.get('/api/locations/findByLocation/'+$scope.f...
      ...
      return something;
 })
 .then(function(something) {
      // so something more
 });
jjabba
  • 494
  • 3
  • 16
1

The call geo.geocode({'address':address},function(results, status){...} is an asynchronous call. It means that it will call the Google Maps API and the next lines of your code will be executed without waiting for the answer.

The second parameter of this call is a callback: function(results, status){...}. This callback is a function that will only be executed when the asynchronous call finishes its process.

In order to make a call to your server after the Google Maps API returns, you need to code this call inside the callback, like that:

geo.geocode({'address':address},function(results, status){
    if (status == google.maps.GeocoderStatus.OK) {
        console.log("Status geocoder OK");
        $scope.form.lat = results[0].geometry.location.lat();
        $scope.form.lng = results[0].geometry.location.lng();

        var latlng = new google.maps.LatLng($scope.form.lat,$scope.form.lng);

        var mapProp = {
                center:latlng,
                zoom:18,
                mapTypeId:google.maps.MapTypeId.ROADMAP,
                mapTypeControl: false
        };

        var map=new google.maps.Map(document.getElementById("map"),mapProp);
        var marker = new google.maps.Marker({
                position: latlng,
                map: map,
                title:name
        });

        //call the server at this point...
        //http.request(options, function(response){...})

    } else {
        alert(status);
    }

  });

You may find more information about http call here.

Marafon Thiago
  • 337
  • 2
  • 6