1

New JS programmer here, and still trying to understand async and await. The following simple example is intended to retrieve the user's location and then update a global variable. I realize that I have to click on the "allow location access" pop-up, but why doesn't the program pause until that happens?

Instead, the callback is skipped (apparently) forever. That is, there is never any output string "In setUserLocation", and the final printed value of userLocation is the same as the original value. No uncaught error shows up in the console (I did have error checks in the original code).

EDIT: I added an error handler callback to getCurrentPosition. Basically, it gets invoked if I click "block access" when prompted to allow access to location. Otherwise the program behaves as before.

  var userLocation = {lat: "40.0", lon: "-90.0", name: "Default Location"}


  function setUserLocation(position) {  // callback function 
                                                                              
      console.log("In setUserLocation")       // never executed -- why?
      lat = position.coords.latitude.toString();
      lon = position.coords.longitude.toString();

      userLocation.lat = lat ;
      userLocation.lon = lon ;
      userLocation.name = "New Location" ;
      console.log(userLocation) ;
  }

  function failedLocation() {
      console.log("Something went wrong")
  }

  async function retrieveLocation() {

      console.log(userLocation) ;
      console.log("Getting location") ;

      await navigator.geolocation.getCurrentPosition(setUserLocation,failedLocation);

      console.log("Got location") ;
      console.log(userLocation) ;
  }

  retrieveLocation() ;

Here is the console output: console output

Grant Petty
  • 1,151
  • 1
  • 13
  • 27
  • Related: https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call – SuperStormer Apr 24 '21 at 18:53
  • 1
    `getCurrentPosition` returns immediately, and "returns" its result by calling the callback. As for why the callback isn't called, I suggest adding an error callback to check. – SuperStormer Apr 24 '21 at 18:54
  • Why make it async? Take async out of the callback. Does it work then? – Reality Apr 24 '21 at 18:57
  • 1
    `await navigator.geolocation.getCurrentPosition(setUserLocation);` - this doesn't _await_ the `setUserLocation` function - instead it awaits the `getCurrentPosition` method which doesn't return a promise, so `await` is useless in this case. Making `setUserLocation` function a `async` is also unnecessary as you don't use the `await` keyword inside it. – Yousaf Apr 24 '21 at 18:58
  • @Reality No, doesn't work. – Grant Petty Apr 24 '21 at 19:00
  • Eliminated the unnecessary `async` from the callback function def. No change in results. – Grant Petty Apr 24 '21 at 19:04
  • Like @SuperStormer said, try adding an error callback to see if it's failing... Also, possibly related: https://stackoverflow.com/questions/3397585/navigator-geolocation-getcurrentposition-sometimes-works-sometimes-doesnt – Reality Apr 24 '21 at 19:05
  • Added error callback - see edit to the original post. – Grant Petty Apr 24 '21 at 19:16

2 Answers2

3

getCurrentPosition doesn't return anything, you have to "promisify" it first:

let getLocation = () => new Promise((resolve, reject) => 
  navigator.geolocation.getCurrentPosition(resolve, reject));

async function main() {
  try {
    console.log('getting location...');
    let location = await getLocation();
    console.log('got location');
    console.log(location)
  } catch (e) {
    console.log('ERROR');
    console.log(e.message)
  }
}


main()
georg
  • 211,518
  • 52
  • 313
  • 390
  • This doesn't work for me either. If I block access on the location pop-up, I get the error, but if I allow, I get no console output. – Grant Petty Apr 24 '21 at 20:11
  • 1
    @GrantPetty: share your OS / browser version. – georg Apr 24 '21 at 20:33
  • Always a good idea. I was wondering if this was a mere problem with the browser. – Reality Apr 24 '21 at 20:37
  • Chrome 89.0.4389.114, MacOS 11.2.3 – Grant Petty Apr 24 '21 at 20:55
  • 2
    Is Chrome enabled in System Preferences > Security & Privacy > Location Services ? – georg Apr 24 '21 at 21:05
  • @georg wouldn't it be a good idea to have the timeout parameter set for this specific reason? However, what confuses me is that the callback doesn't fire yet they still get the coordinates. – Reality Apr 24 '21 at 21:08
  • OK, this is weird: NO, it was not enabled. I reset it, and the script finally produced the output from the callback. But then it stopped working, and I found Locations Services for Chrome unchecked again.. Reset several times, and each time it would belatedly display the callback output, but then clicking on the access pop-up ALLOWING caused the security setting to be reset to unchecked! Even though I had locked against further changes. I have no idea what's going on. – Grant Petty Apr 24 '21 at 21:14
  • @Reality I'm not getting the coordinates. Only the default coordinates that were set prior to the callback. – Grant Petty Apr 24 '21 at 21:15
  • This seems to be the problem I'm seeing with security preferences: https://discussions.apple.com/thread/252188240 – Grant Petty Apr 24 '21 at 21:17
  • @GrantPetty that would explain everything. Yeah, `getCurrentPosition` accepts an object that allows a timeout property that would be great to stop waiting after a certain amount of time. – Reality Apr 24 '21 at 21:19
  • Updating Chrome seems to have fixed the problem with the location access box getting unchecked! The callback now gets invoked and the data printed. HOWEVER, it's still occurring out of the desired order. – Grant Petty Apr 24 '21 at 21:25
  • @GrantPetty: yes, this is because your code is wrong. Have you tested the snippet I posted? – georg Apr 24 '21 at 21:36
1

The reason why my callback function was never getting executed at all apparently had to do with location access by Chrome being unchecked in my Mac's Security Preferences under Big Sur. The remaining mystery was then why manually re-checking was not sticking -- it kept reverting to unchecked. That turns out to have been described as a bug here:

https://discussions.apple.com/thread/252188240

Updating Chrome solved that problem, and the callback now executes. However, I still have the problem that it doesn't execute in the desired order, so rather than edit this question (which might be relevant to others coming here), I thought I'd post a new one with the updated (different) question.

Grant Petty
  • 1,151
  • 1
  • 13
  • 27