patternjavascriptMinor
Using JavaScript promises to display weather and location information
Viewed 0 times
javascriptpromisesinformationusinganddisplaylocationweather
Problem
This is the first time I'm trying to use promises in JavaScript so I'm not sure if I have done it correctly, but it seems to work. The problem is that I have ended up with a "nested
I am using the
What I would like it to look like would be something like:
But it doesn't seem to work with two calls in
This is my current solution:
when" and it doesn't look that great. There probably is a nicer solution out there. I would really appreciate some feedback on how I can improve my code.I am using the
navigator.geolocation to get the position and then I'm using two different APIs to get the current weather and the address of the location. What I would like it to look like would be something like:
$.when(getPosition())
.then(getWeather(position),getLocationName(position))
.done(displayWeather);But it doesn't seem to work with two calls in
then() like you can have in when(). This is my current solution:
var displayWeather = function(weatherData, locationData) {
$('#userLocation').text(locationData.results[3].formatted_address);
$('#weatherDescription').text(weatherData.currently.temperature);
$('#temperature').text(weatherData.currently.summary);
}
var getPosition = function() {
var deferred = $.Deferred();
navigator.geolocation.getCurrentPosition(deferred.resolve, deferred.reject);
return deferred.promise();
};
var getWeather = function(position) {
return $.getJSON('https://api.forecast.io/forecast/{APIKEY}/' + position.coords.latitude + ',' + position.coords.longitude + '?callback=?')
.then(function(data) {
return data;
});
}
var getLocationName = function(position) {
return $.getJSON('https://maps.googleapis.com/maps/api/geocode/json?latlng=' + position.coords.latitude + ',' + position.coords.longitude + '&key={APIKEY}')
.then(function(data) {
return data;
});
}
$(document).ready(function() {
$.when(getPosition())
.done(function(position) {
$.when(getWeather(position), getLocationName(position)).done(displayWeather);
});
});Solution
$.when(getPosition())$.when is only used when listening to multiple promises. Since getPosition is just one and it already returns a promise, $.when isn't required and you can simply chain then to getPosition().var getWeather = function(position) {
return $.getJSON('https://api.forecast.io/forecast/{APIKEY}/' + position.coords.latitude + ',' + position.coords.longitude + '?callback=?')
.then(function(data) {
return data;
});
}
var getLocationName = function(position) {
return $.getJSON('https://maps.googleapis.com/maps/api/geocode/json?latlng=' + position.coords.latitude + ',' + position.coords.longitude + '&key={APIKEY}')
.then(function(data) {
return data;
});
}Attaching
then which just returns the resolved data data is unnecessary. $.getJSON already returns a promise-like object that resolves to data. Any then attached to it will get data in the same way this then receives it.Additionally, suggesting you use
then instead of the jQuery-specific done. then is standard, and allows you to easily move over to the standard Promises.I usually recommend pushing off the "flow logic" of promises to the caller instead of spreading it across different functions. This allows you to easily write functions as promise-returning operations while keeping all the "flow logic" in one place.
On other stuff, suggesting you move the url into a variable. This keeps your AJAX operation short and free from the string concatenation madness. A;so recommending using named function instead of function expressions. They're easier to debug as their names appear in the stack trace.
Your code could be simplified into:
function getPosition () {
return $.Deferred(function(deferred){
navigator.geolocation.getCurrentPosition(deferred.resolve, deferred.reject);
}).promise();
};
function getWeather (position) {
var url = 'https://api.forecast.io/forecast/{APIKEY}/' + position.coords.latitude + ',' + position.coords.longitude + '?callback=?'
return $.getJSON(url);
}
function getLocationName (position) {
var url = 'https://maps.googleapis.com/maps/api/geocode/json?latlng=' + position.coords.latitude + ',' + position.coords.longitude + '&key={APIKEY}';
return $.getJSON(url);
}
$(document).ready(function() {
getPosition().then(function(position){
return $.when(getWeather(position), getLocationName(position));
}).then(function(weatherData, locationData){
$('#userLocation').text(locationData.results[3].formatted_address);
$('#weatherDescription').text(weatherData.currently.temperature);
$('#temperature').text(weatherData.currently.summary);
});
});If you can write using ES6, the code becomes simpler and you can drop the jQuery dependency for the data gathering functions. ES6 now has native promises as well as template strings, and modern browsers have
fetch. This reduces jQuery footprint to only the DOM-interacting operations.function getPosition() {
return new Promise((resolve, reject) => navigator.geolocation.getCurrentPosition(resolve, reject));
};
function getWeather(position) {
const url = 'https://api.forecast.io/forecast/${APIKEY}/${position.coords.latitude},${position.coords.longitude}?callback=?';
return fetch(url).then(response => response.json());
}
function getLocationName(position) {
const url = 'https://maps.googleapis.com/maps/api/geocode/json?latlng=${position.coords.latitude},${position.coords.longitude}&key=${APIKEY}';
return fetch(url).then(response => response.json());
}
$(document).ready(function() {
getPosition()
.then(position => Promise.all(getWeather(position), getLocationName(position)))
.then(function(data){
const weatherData = data[0];
const locationData = data[1];
$('#userLocation').text(locationData.results[3].formatted_address);
$('#weatherDescription').text(weatherData.currently.temperature);
$('#temperature').text(weatherData.currently.summary);
});
});Code Snippets
$.when(getPosition())var getWeather = function(position) {
return $.getJSON('https://api.forecast.io/forecast/{APIKEY}/' + position.coords.latitude + ',' + position.coords.longitude + '?callback=?')
.then(function(data) {
return data;
});
}
var getLocationName = function(position) {
return $.getJSON('https://maps.googleapis.com/maps/api/geocode/json?latlng=' + position.coords.latitude + ',' + position.coords.longitude + '&key={APIKEY}')
.then(function(data) {
return data;
});
}function getPosition () {
return $.Deferred(function(deferred){
navigator.geolocation.getCurrentPosition(deferred.resolve, deferred.reject);
}).promise();
};
function getWeather (position) {
var url = 'https://api.forecast.io/forecast/{APIKEY}/' + position.coords.latitude + ',' + position.coords.longitude + '?callback=?'
return $.getJSON(url);
}
function getLocationName (position) {
var url = 'https://maps.googleapis.com/maps/api/geocode/json?latlng=' + position.coords.latitude + ',' + position.coords.longitude + '&key={APIKEY}';
return $.getJSON(url);
}
$(document).ready(function() {
getPosition().then(function(position){
return $.when(getWeather(position), getLocationName(position));
}).then(function(weatherData, locationData){
$('#userLocation').text(locationData.results[3].formatted_address);
$('#weatherDescription').text(weatherData.currently.temperature);
$('#temperature').text(weatherData.currently.summary);
});
});function getPosition() {
return new Promise((resolve, reject) => navigator.geolocation.getCurrentPosition(resolve, reject));
};
function getWeather(position) {
const url = 'https://api.forecast.io/forecast/${APIKEY}/${position.coords.latitude},${position.coords.longitude}?callback=?';
return fetch(url).then(response => response.json());
}
function getLocationName(position) {
const url = 'https://maps.googleapis.com/maps/api/geocode/json?latlng=${position.coords.latitude},${position.coords.longitude}&key=${APIKEY}';
return fetch(url).then(response => response.json());
}
$(document).ready(function() {
getPosition()
.then(position => Promise.all(getWeather(position), getLocationName(position)))
.then(function(data){
const weatherData = data[0];
const locationData = data[1];
$('#userLocation').text(locationData.results[3].formatted_address);
$('#weatherDescription').text(weatherData.currently.temperature);
$('#temperature').text(weatherData.currently.summary);
});
});Context
StackExchange Code Review Q#129544, answer score: 4
Revisions (0)
No revisions yet.