I wonder if it's possible to wrap Geolocation.watchPosition()
https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/watchPosition in a Promise and use it with async/await
idioms in a way it does it's work; constantly returns positions whenever a device's location changes and invokes succeeding functions.
// Example Class
class Geo {
// Wrap in Promise
getCurrentPosition(options) {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject, options)
})
}
// Wrap in Promise
watchCurrentPosition(options) {
return new Promise((resolve, reject) => {
navigator.geolocation.watchPosition(resolve, reject, options)
})
}
// Works well.
async currentPosition() {
try {
let position = await this.getCurrentPosition()
// do something with position.
}
catch (error) {
console.log(error)
}
}
// Any way...?
async watchPosition() {
try {
let position = await this.watchCurrentPosition()
// do something with position whenever location changes.
// Invoking recursively do the job but doesn't feel right.
watchPosition()
}
catch (error) {
console.log(error)
}
}
}
Not yet.
The pattern you're describing is an Observable - there isn't language support for it in Javascript, but it's coming.
In ES2015 we got generators: function*
& yield
, which allowed Iterators - pulling each yield
with a for
...of
loop.
Generators also support push Observers, with var valToGet = yield foo;
and generator.next(valToPush);
syntax.
Generators are synchronous - they're just passing a single thread back and forth.
In ES2017 we got async
& await
- these use generators under the covers to convert each await
in an async function
into a yield new Promise(...
. The async function
becomes a iterator of promises.
Ideally we would be able to do something like this:
async watchPosition*() {
try {
while(this.enabled) {
// Loop each time navigator.geolocation.watchPosition fires success
const position = await this.watchCurrentPosition();
// Pass back to the listener until generator.next
const atDestination = yield position;
if(atDestination)
break; // We're here, stop watching
}
}
catch (error) {
console.log(error)
}
}
Unfortunately, async function*
isn't supported yet - functions can be generators or async
, but not both. There also isn't the nice for
...of
syntax like there is for iterators, just the clunky generator.next(pushValue)
, so consuming this hypothetical method is a little ugly:
async listener() {
const generator = Geo.watchPosition();
let item = await generator.next(false);
while (!item.done) {
// Update UI
const atDestination = areWeThereYet(item.value);
item = await generator.next(atDestination);
}
}
So asynchronous iterators/observables are coming, but there's lots to sort out first.
In the mean time there are some exceptional libraries that support observer patterns and are available now, such as RxJS.