unable to cope with the asynchronous nature of navigator.geolocation

て烟熏妆下的殇ゞ 提交于 2019-11-27 04:55:53

Yes you have a problem with the callback nature of the operation. You cannot call the getCurrentLocation() function and expect that it will return synchronously. I am even surprised that it did work occasionally.

You have to use a slightly different paradigm when working with asynchronous calls. You should probably call your function, plotCurrentLocation() and do something like the following example:

function plotCurrentLocation(map) {
   if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(function(position) {
         var currLocation = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);

         // plot the currLocation on Google Maps, or handle accordingly:

         new google.maps.Marker({ title: 'Current Location',
                                  map: map, 
                                  position: currLocation });

         map.setCenter(currLocation);
      });
   }
}

Note how the map parameter passed to the plotCurrentLocation() function is available to the inner functions within. This works because JavaScript has closures.


UPDATE:

The callback method suggested by the other answers is another option to tackle this, by adding another layer of abstraction.

You're trying to make it synchronous, and it won't work. As you've seen, there is no guarantee currLocation is set when the function returns. You probably now have something like:

var loc = getCurrentLocation();
//doSomethingWith loc

Change your function to:

function getCurrentLocation(callback) {
   if(navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(function(position) {
         callback(new google.maps.LatLng(position.coords.latitude,
                                       position.coords.longitude));
       });
    }
    else {
       throw new Error("Your browser does not support geolocation.");     
    }
}     

and the client code to:

getCurrentLocation(function(loc)
{
  //doSomethingWith loc
});

Better to use:

<script type="text/javascript">
function getCurrentLocation(callback) {
  if(!navigator.geolocation) return;
  navigator.geolocation.getCurrentPosition(function(position) {
    var currLocation = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
    callback(currLocation);
  });
}
</script>

...

<script type="text/javascript">
getCurrentLocation(function(currLocMap){
  // do something with map now that it is ready..
});
</script>

You can use Promise:

var lat,lon;
var promise1 = new Promise(function(resolve, reject) {
    navigator.geolocation.getCurrentPosition(function(pos){
        lat = pos.coords.latitude
        lon = pos.coords.longitude
        resolve({lat,lon});
    }) 
})

promise1.then(function(value) {
      console.log(value.lat,value.lon)  
});

You could also write a wrapper function for getCurrentPosition

requestPosition() {

  // additionally supplying options for fine tuning, if you want to
  var options = {
    enableHighAccuracy: true,
    timeout:    5000,   // time in millis when error callback will be invoked
    maximumAge: 0,      // max cached age of gps data, also in millis
  };

  return new Promise(function(resolve, reject) {
    navigator.geolocation.getCurrentPosition(
      pos => { resolve(pos); }, 
      err => { reject (err); }, 
      options);
  });
}

This allows you to choose how to handle it (async/await, then(), whatever); for example

async componentDidMount(){

  position = await requestPosition();

}

Isn't that gorgeous :-)

(Just wanted to add to @AymanBakris answer, but all of that would have been quite awkward in one single comment ^^)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!