не в состоянии справиться с асинхронной природой navigator.geolocation - PullRequest
5 голосов
/ 25 апреля 2010

Я использую API-интерфейс navigator.geolocation.getCurrentPosition (function) в firefox 3.6. Когда я пытаюсь вызвать этот метод несколько раз, я вижу, что иногда он работает, а иногда нет. Я понял, что проблема заключается в асинхронном обратном вызове. Я вижу, что в некоторый момент вызывается функция обратного вызова, но моя внешняя функция уже завершается, поэтому я не могу поймать значения координат позиции.

Я довольно новичок в javascript, поэтому я предполагаю, что другие кодировщики javascript, возможно, уже выяснили, как с этим бороться. Пожалуйста, помогите.

Редактировать: вот пример кода, который я использую

<script type="text/javascript">
   function getCurrentLocation() {
     var currLocation;
      if(navigator.geolocation) {
         navigator.geolocation.getCurrentPosition(function(position) {
          currLocation = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
        });
       }
       return currLocation; // this returns undefined sometimes. I need help here
}    
</script>

Редактировать 2: Спасибо всем за ответы, я хотел бы выбрать все ответы как «принятые», но не могу этого сделать.

Теперь я столкнулся с другой проблемой. Я вызываю navigator.geolocation.getCurrentPosition каждые 3 секунды, но ответы прекращаются после 10 - 15 ответов. У кого-нибудь есть идеи?

еще раз спасибо

Ответы [ 5 ]

5 голосов
/ 25 апреля 2010

Вы пытаетесь сделать это синхронно, и это не сработает. Как вы видели, нет гарантии, что currLocation будет установлен, когда функция вернется. У вас, вероятно, сейчас есть что-то вроде:

var loc = getCurrentLocation();
//doSomethingWith loc

Измените свою функцию на:

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.");     
    }
}     

и код клиента:

getCurrentLocation(function(loc)
{
  //doSomethingWith loc
});
4 голосов
/ 25 апреля 2010

Да, у вас проблема с характером операции обратного вызова. Вы не можете вызвать функцию getCurrentLocation() и ожидать, что она вернется синхронно. Я даже удивлен, что это иногда срабатывало.

При работе с асинхронными вызовами необходимо использовать немного другую парадигму. Вероятно, вам следует вызвать вашу функцию plotCurrentLocation() и сделать что-то вроде следующего примера:

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);
      });
   }
}

Обратите внимание, как параметр map, переданный в функцию plotCurrentLocation(), доступен для внутренних функций внутри. Это работает, потому что JavaScript имеет замыканий .


UPDATE:

Метод обратного вызова, предложенный другими ответами, является еще одним вариантом решения этой проблемы, добавив еще один уровень абстракции.

3 голосов
/ 25 апреля 2010

Лучше использовать:

<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>
2 голосов
/ 04 апреля 2019

Вы можете использовать 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)  
});
0 голосов
/ 19 апреля 2019

Вы также можете написать функцию оболочки для 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);
  });
}

Это позволяет вам выбрать способ обработки (async/await, then(), что угодно); например

async componentDidMount(){

  position = await requestPosition();

}

Разве это не великолепно: -)

(Просто хотел добавить к ответу @AymanBakris, но все это было бы довольно неудобно в одном комментарии ^^)

...