0

The getLocation() function that should retrieve location in 3 attempts returns undefined instead. navigator.geolocation.getCurrentPosition() returns the correct position, but the problem is in the promise handling.

The problem is apparently that I am calling a promise inside promise. I am not allowed to use the await keyword inside geolocate() already declared as async.

Original call:

var getLocationPromise = this.getLocation(); // Do something... location = await getLocationPromise; 

getLocation():

 async getLocation() { return new Promise((resolve, reject) => { var geolocate; for (let i=0; i<3; i++) { geolocate = this.geolocate(); try { var location = geolocate;//CAN'T USE AWAIT INSIDE ASYNC... resolve(location); } catch(err) { continue; } } reject("Max geolocation attempts"); }); } 

geolocate():

 async geolocate() { return new Promise((resolve, reject) => { navigator.geolocation.getCurrentPosition( (position) => { resolve(position); }, (err) => { reject(err); }, {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000} ); }); } 
7
  • 1
    await getLocation().then(); === await getLocation(); - doesn't it? Commented Jan 4, 2017 at 9:21
  • It gives different results. I had problem with await getLocation(); returning undefined, so I use await getLocation().then(); that seems safer Commented Jan 4, 2017 at 9:24
  • not sure why you use async on geolocate and getLocation - as neither of those functions use await Commented Jan 4, 2017 at 11:31
  • 1
    //CAN'T USE AWAIT INSIDE ASYNC - no, that's not right, you can ONLY use await inside async Commented Jan 4, 2017 at 12:02
  • That's the problem, can't await in async Commented Jan 4, 2017 at 12:11

2 Answers 2

2

As long as the following is in a function declared async

var getLocationPromise = this.getLocation(); // Do something... location = await getLocationPromise; 

it should be fine as is

looking at getLocation/geolocate, unless you need a separate geolocate method, they should be able to be combined and simplified to

getLocation() { var geolocate = () => new Promise((resolve, reject) => navigator.geolocation.getCurrentPosition(resolve, reject, { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 }); ); // this function will "retry" the supplied function (fn) cont times var limitedPromiseRetry = (fn, cont) => fn().catch(err => cont > 0 ? limitedPromiseRetry(fn, cont-1) : Promise.reject('Max number of geolocation attempts')); return limitedPromiseRetry(geolocate, 3); } 
Sign up to request clarification or add additional context in comments.

2 Comments

Nice and compact solution, it avoids using the double promise. From your response I understand that putting promise inside promise is not a good idea and is not supported?
no, it is supported, it's just not required in this case
1

async and await

You can not use await inside functions without the async keyword. So the error occurs because the executor function is not async:

var getLocation = async function(){ // <-- this function has "async" keyword, but ... return new Promise( function( resolve, reject ){ // <-- ... this "executor" function has no "async" keyword. var value = await geolocate(); // <-- ERROR: await is only valid in async function. resolve( value ); }) }; 

But you should not make the promise executor an async function.
See https://eslint.org/docs/rules/no-async-promise-executor for more info.

new Promise( async function( resolve, reject ){ // <-- BAD ! Don't do it ! ... }) 

without nested promise

But as getLocation is a promise already, you do not need the nested new Promise( ... ) at all:

var getLocation = async function(){ // <-- "async" makes a function to be a promise var value = await geolocate(); // "return value" inside async function is "the same" as // "resolve( value )" in a promise return value; }; 

So, theoretically, you could solve your problem in the following way (although there are probably better ways of doing it. For 'rejecting' inside async function, see also How to reject in async/await syntax?).

var getLocation = async function(){ for( let i = 0; i < 3; i++ ){ try { console.log('try ...', i); var location = await geolocate(i); console.log('... success'); return location; } catch(err) { console.log('... next try'); continue; } } return Promise.reject('no success'); }; getLocation().then(function(result){ console.log('then:', result); }).catch(function(reason){ console.log('error:', reason); }) 

nested Promises

Promises inside promises are ok.
Note that resolving promises with resolved promises behaves "the same" as resolving only one promise. You will not notice any difference in the .then() function, no matter if you resolve a value, or a resolved promise inside a promise, ... and so on.

var nestedPromises = new Promise( function( resolve1, reject1 ){ resolve1( new Promise( function( resolve2, reject2 ){ resolve2( new Promise( function( resolve3, reject3 ){ resolve3('resolved value'); })); })); }); nestedPromises.then( function( value ){ console.log('value:', value); // <-- "value: resolved value" }) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.