Возможно ли получить местоположение GPS из браузера на заднем плане в фоновом режиме? - PullRequest
7 голосов
/ 04 ноября 2019

У меня есть веб-приложение, которое запрашивает у пользователя местоположение GPS. Он работает нормально, используя довольно стандартный код, который выглядит примерно так:

function getpos_callback( a ) {
    top.location.href = 'location.php?lat=' + a.coords.latitude + '&lon=' + a.coords.longitude;
}

function error_callback( er ) {
    top.location.href = 'location.php?err=1';
}

if ( 'geolocation' in navigator ) {
    navigator.geolocation.getCurrentPosition( getpos_callback, error_callback, {
        enableHighAccuracy: true,
        maximumAge: 300000,      // 300 seconds = 5 min = max age of cached value to use
        timeout: 8000,           // 8 seconds
    } );
}

Вот проблема: в настольном браузере это может занять довольно много времени (4-6 секунд и до 8, вкод), чтобы определить местоположение. Даже с мобильным иногда это может быть вялым. Эти секунды кажутся вечностью, когда пользователь просто хочет продолжить пользоваться сайтом.

Я хотел бы сразу позволить пользователю войти, но каким-то образом «вызвать задачу», чтобы спроситьбраузер для определения местоположения в фоновом режиме, а затем передать его мне в фоновом режиме при получении местоположения.

Возможно ли это?

Ответы [ 4 ]

6 голосов
/ 15 ноября 2019

Метод getCurrentPosition является асинхронным по определению. Это указано W3C, чтобы вернуться немедленно. Вы можете проверить спецификацию для деталей.

Итак, вы можете просто вызвать функцию, которая «впускает пользователя» сразу после вызова getCurrentPosition перед вызовом успешного обратного вызова. Когда вы это сделаете, метод getCurrentPosition уже будет «порождать задачу» в фоновом режиме.

Проблема в вашем коде заключается в том, что вы меняете URL-адрес веб-страницы после получения обратного вызова внутриgetpos_callback функция. Я предлагаю вам изменить это поведение, обновляя состояние пользовательского интерфейса с помощью JS вместо перезагрузки страницы с параметрами lat / lng.

Рефакторинг вашего кода будет выглядеть так:

function getpos_callback( a ) {
    // Comment the line bellow to avoid loading the page
    // top.location.href = 'location.php?lat=' + a.coords.latitude + '&lon=' + a.coords.longitude;
    updateScreen(a.coords.latitude, a.coords.longitude);
}

function updateScreen(lat, lon) {
    // Update the UI with the lat/lon received instead of getting it from the URL
}

function error_callback( er ) {
    top.location.href = 'location.php?err=1';
}

function showUI() {
    // "let the user in right away"
}

if ( 'geolocation' in navigator ) {
    navigator.geolocation.getCurrentPosition( getpos_callback, error_callback, {
        enableHighAccuracy: true,
        maximumAge: 300000,      // 300 seconds = 5 min = max age of cached value to use
        timeout: 8000,           // 8 seconds
    } );
    showUI();
}
else { error(); }
4 голосов
/ 14 ноября 2019

Нет, для этого не существует способа "порождать" процесс в фоновом режиме и позволить пользователю продолжить навигация = обновить страницу .

лучший способ сделать то, что вы хотите, это сделать ваше веб-приложение одностраничным приложением , что означает, что все действия выполняются с помощью запросов AJAX.

В этом случаеВы должны использовать только AJAX-запросы для всех действий:

  • отправка форм,
  • вход в систему,
  • посещениедругое представление
  • и т. д.

, а затем измените html-страницу.

Отправка местоположения также выполняется с помощью запроса AJAX:

function getpos_callback( a ) {
    //top.location.href = 'location.php?lat=' + a.coords.latitude + '&lon=' + a.coords.longitude;
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if (xhr.readyState == XMLHttpRequest.DONE) {
            console.log('done');
        }
    }
    xhr.open('GET', 'location.php?lat=' + a.coords.latitude + '&lon=' + a.coords.longitude, true);
    xhr.send(null);
}

function error_callback( er ) {
    // top.location.href = 'location.php?err=1';
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if (xhr.readyState == XMLHttpRequest.DONE) {
            console.log('done');
        }
    }
    xhr.open('GET', 'location.php?err=1', true);
    xhr.send(null);
}

if ( 'geolocation' in navigator ) {
    navigator.geolocation.getCurrentPosition( getpos_callback, error_callback, {
        enableHighAccuracy: true,
        maximumAge: 300000,      // 300 seconds = 5 min = max age of cached value to use
        timeout: 8000,           // 8 seconds
    } );
}

Вы можете сохранить местоположение в сеансе с отметкой времени с истекшим сроком, и, если пользователь повторно посетит страницу, запросите ее только в том случае, если срок ее действия истек.

Для сохранения истории и функции кнопки возврата для браузера, вы можете установить Url Hash для каждого просмотра.

1 голос
/ 13 ноября 2019

Вы можете добавить функцию giolocation в document.ready, а в функцию callback вы можете вызвать свой метод примерно так:

$(document).ready(function() {
 setTimeout(() => {
  if (navigator.geolocation) {
   navigator.geolocation.getCurrentPosition(function(position) {
    alert('This will call when you have giolocation Lat is ' + position.coords.latitude + ' Lon is ' + position.coords.latitude)
   });
  } else {
   alert("Browser does not support HTML5 geolocation.");
  }
 }, 500);
 alert('Rest of things loded in in background')
});

Я добавил установленное время ожидания, чтобы показать, что сайт загружается во время работы службы giolocation. в фоновом режиме

Здесь работает пример https://jsfiddle.net/csbp2ey5/

1 голос
/ 13 ноября 2019

По сути, на мой взгляд, для вашего случая лучше всего использовать событие window.onload. Из этого означало, что вы загружаете геолокацию после всего, что в документе загружено. Это потому, что вы можете позволить посетителю просматривать страницу во время инициализации GPS.

Для создания истинного потока вы можете использовать Worker, но Worker не имеет доступа к объекту "геолокации" объекта "навигатор". Но это может измениться в будущем.

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

setTimeOut (), вероятно, не лучший для вас. Хотя setTimeOut () может задержать выполнение кода и не блокирует основной поток при его первом вызове, он все равно будет блокировать основной поток позже в любом случае, когда наступит его очередь.

Несколько ссылок для вас:

Веб-работники - как они работают? - В настоящее время это не сработает для вашего случая, но кто знает о будущем.

Как сформулироватьразница между асинхронным и параллельным программированием? - асинхронные функции не являются истинным параллелизмом, но могут работать в вашем случае, поскольку не блокируют основной поток.

Как работают setInterval и setTimeout? - setTimeOut (), вероятно, не подходит для вашего случая использования, но стоит упомянуть.

https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/watchPosition - Использование watchPosition. Если вы пользуетесь GPS, это может понадобиться вам в будущем.

Пример кода window.onload:

 <!DOCTYPE html>
<html>
<body>

<script>
function getpos_callback( a ) {
    top.location.href = 'location.php?lat=' + a.coords.latitude + '&lon=' + a.coords.longitude;
}

function error_callback( er ) {
    top.location.href = 'location.php?err=1';
}

function getGPS(){
    if ( 'geolocation' in navigator ) {
        navigator.geolocation.getCurrentPosition( getpos_callback, error_callback, {
            enableHighAccuracy: true,
            maximumAge: 300000,      // 300 seconds = 5 min = max age of cached value to use
            timeout: 8000,           // 8 seconds
        });
    }
}

/*
 * Attach getGPS to the window.onload event.
 *
 */
if ( window.addEventListener ) {
    window.addEventListener('load', getGPS);
} else {
    window.attachEvent('onload', getGPS);
}
</script>

</body>
</html> 
...