Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to fetch GPS location from desktop browser in the background?

I have a web app that asks the user for their GPS location. It works fine using pretty standard code that looks something like this:

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

Here's the problem: on a desktop browser, it can take quite some time (4-6 seconds, and as long as 8, per the code) to determine the location. Even with mobile sometimes it can be sluggish. These seconds feel like an eternity when the user just wants to get on with using the site.

What I'd like to do is let the user in right away, but somehow "spawn a task" to ask the browser for the location in the background, and then have it pass that location to me in the background when the location is retrieved.

Is this possible?

like image 839
Eric Avatar asked Nov 04 '19 17:11

Eric


2 Answers

The method navigator.geolocation.getCurrentPosition is asynchronous by definition. It's specified by W3C to return immediately. You can check the specification for details.

So, you can simply call the function that "let the user in" right after calling getCurrentPositionbefore having the success callback being called. The method getCurrentPosition will have already "spawn a task" in the background when you do that.

The problem in your code is that you're changing the URL of the webpage after receiving the callback, inside the getpos_callback function. I suggest you to change this behavior by updating the UI state using JS instead of reloading the page with the lat/lng parameters.

Refactoring your code, it would look like:

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(); }
like image 74
Italo Borssatto Avatar answered Sep 20 '22 22:09

Italo Borssatto


No, there is no way to "spawn" a process on the background for this and let the user continue navigating=refresh the page.

The best way to do what you want is to make your web application a Single page application, meaning all actions are done by making AJAX requests.

In this case, you must only use AJAX requests for all actions:

  • submitting forms,
  • logging in,
  • visiting another view
  • etc

and then change the page html.

Submitting the location is also done via AJAX request:

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

You can store the location in the session with an expired timestamp and if the user revisits the page, request it only if it has expired.

For keeping history and back button functionality for the browser, you can set the Url Hash for each view.

like image 40
Jannes Botis Avatar answered Sep 19 '22 22:09

Jannes Botis