最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Is it possible to fetch GPS location from desktop browser in the background? - Stack Overflow

programmeradmin1浏览0评论

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?

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?

Share Improve this question edited Nov 18, 2019 at 14:09 Italo Borssatto 15.7k7 gold badges67 silver badges90 bronze badges asked Nov 4, 2019 at 17:52 EricEric 5,21510 gold badges45 silver badges74 bronze badges 1
  • Can you provide more details on what Framework/Platform you're using? – akseli Commented Nov 13, 2019 at 1:57
Add a ment  | 

4 Answers 4

Reset to default 6 +100

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

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.

Essentially, in my opinion, for your case, I think it is best to use the window.onload event. Of which meant that you load your geolocation after everything in the document loaded. That is because you can let the visitor browse the page while the GPS is initializing.

For spawning true thread you can use Worker but Worker does not have access the "geolocation" object of the "navigator" object. But that may change in the future.

async functions may work for your case as it does not block the main thread. However, I still think it is best to run the getCurrentPosition() after the page is loaded.

setTimeOut() is probably not the best for you. Although setTimeOut() can delay code execution and does not block the main thread when it is first called, it will still block the main thread later anyway when it is it turn to get executed.

A few reference for you:

Web workers - How do they work? - This, currently will not work for your case but who know about the future.

How to articulate the difference between asynchronous and parallel programming? - async functions are not true parallelism but may work for your case as it will not block the main thread.

How does setInterval and setTimeout work? - setTimeOut() probably is not a the right one for your usage case but worth mentioning.

https://developer.mozilla/en-US/docs/Web/API/Geolocation/watchPosition - The use of watchPosition. If you are into GPS, you may need this in the future.

Example window.onload code:

 <!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> 

You can add giolocation function in document.ready and in callback function you can call your method something like this

$(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')
});

I have added set time out for showing that site is loading while giolocation service is running in background

Here is working example https://jsfiddle/csbp2ey5/

发布评论

评论列表(0)

  1. 暂无评论