This code is for a 'zillow' clone as a portfolio project.
My issue: I made a promise that retrieves the user's location using the geolocation API. I need this code to run asynchronously however, when the code executes, it resolves the promise before the user's location is found. The code works when I wrap certain parts of it in a timeout function but I really want to figure this out with using only promises. How do I fix this issue? Help is super appreciated!
PS: I have not programmed my error handling yet, I wanted to get the above issue out of the way before doing so. Also, if you need any other files just let me know and I will upload them however, I think the issue is in either of the two files that are displayed below
Below is code from my 'controller.js' file:
const controlSearchCurrentLocation = async function () {
await findLocationView.getUserLocation(model.storeCurrentLocation);
/*
The setTimeout function is only used in order to give the
'findLocationView.getUserLocation(model.storeCurrentLocation)' time
to find and store the user's location
*/
setTimeout(() => {
currentCityResultsView.displayResults(
model.sendCurrentCityState,
model.storeData,
model.sendCoords,
model.sendHomesCurrentLocation,
model.sendHomesLength
);
}, 4000);
};
const init = function () {
controlSearchCurrentLocation();
controlSearch();
};
init();
Below is from my 'findLocationView.js' file:
class FindLocationView extends AppView {
getUserLocation(storeCurrentLocationFunc) {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(
function (position) {
this._success(position, storeCurrentLocationFunc);
}.bind(this),
this._failure,
this._options
);
if (navigator.geolocation) resolve("stored user location");
if (!navigator.geolocation) reject("could not store user location");
});
}
async _success(position, storeCurrentLocationFunc) {
let city, state;
const { latitude, longitude } = position.coords;
[...this._coordinates] = [latitude, longitude];
[this._latitude, this._longitude] = [latitude, longitude];
mapView.initMap(this._coordinates);
const data = await helpers.ajaxLocation(this._latitude, this._longitude);
city = data.results[0].address_components[2].long_name;
state = data.results[0].address_components[4].short_name;
storeCurrentLocationFunc(this._coordinates, city, state);
}
_failure(error) {
console.warn(`ERROR(${error.code}): ${error.message}`);
}
_options = {
enableHighAccuracy: true,
};
}
export default new FindLocationView();
Ok, so I seem to have found a solution. If I can do anything to make this better, or if there is another solution please let me know. Thanks!
Controller: Mostly the same however, I no longer need the setTimeout function since the controlSearchCurrentLocation function seems to be executing code asynchronously.. (see below)
const controlSearchCurrentLocation = async function () {
await findLocationView.getUserLocation(model.storeCurrentLocation);
currentCityResultsView.displayResults(
model.sendCurrentCityState,
model.storeData,
model.sendCoords,
model.sendHomesCurrentLocation,
model.sendHomesLength
);
};
const init = function () {
controlSearchCurrentLocation();
controlSearch();
};
init();
My biggest correction was here in my findLocationView class. Rather than resolving the promise outside of the getCurrentPosition function, I passed it into the function and I have it executing the '_success' function upon resolving. This makes it impossible for the promise to resolve before the user's location is found.
class FindLocationView extends AppView {
getUserLocation(storeCurrentLocationFunc) {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(
function (position) {
resolve(this._success(position, storeCurrentLocationFunc));
}.bind(this),
this._failure,
this._options
);
if (!navigator.geolocation) reject("could not store user location");
});
}
async _success(position, storeCurrentLocationFunc) {
let city, state;
const { latitude, longitude } = position.coords;
[...this._coordinates] = [latitude, longitude];
[this._latitude, this._longitude] = [latitude, longitude];
mapView.initMap(this._coordinates);
const data = await helpers.ajaxLocation(this._latitude, this._longitude);
city = data.results[0].address_components[2].long_name;
state = data.results[0].address_components[4].short_name;
storeCurrentLocationFunc(this._coordinates, city, state);
}
_failure(error) {
console.warn(`ERROR(${error.code}): ${error.message}`);
}
_options = {
enableHighAccuracy: true,
};
}
export default new FindLocationView();
Although you managed to solve. The reason you ended up with the problem is from mixing concerns.
const userLocation = await findLocationView.getUserLocation();
Ideally you want getUserLocation to resolve the position, nothing else. It doesn't store the location.
navigator.geolocation.getCurrentPosition(resolve, reject);
Now you have a separation of concern
// getUserLocation no longer takes a param
const userLocation = await findLocationView.getUserLocation();
// Wait until userLocation is stored
await _success(userLocation, model.storeCurrentLocation);
// We can now show results
currentCityResultsView.displayResults();
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.