I am trying to create a weather report application using vanilla JS and APIs. My goals are:
- When web page finishes loading I want to ask user for their location.
- If the user accepts the request a. I want to get their coordinates using browser api and store the latitude and longitude and then run another async function which will be fetching data from OpenWeather api using those latitute and longitude data. b. Update the UI accordingly.
- If the user blocks the request: a. I want to still fetch data from OpenWeather api but this time using default values of latitude and longitude (for e.g Paris)
The problems I'm facing are:
- I'm trying to get geolocation using a promisified function. So this is will be executed in async function if using async/await but I am unable to run two async functions one after another finishes executing so that it can use previously executed function's response data.
- If user block the location in the browser the function will be rejected and the catch block will be executed, so should I place the weather api function in the catch block to use the default latitude and longitude value or do something else?
- As much I know, executing more than one async functions serially have no gaurantee that result will come in the same order, so sometimes weather api functions successfully fetches data from api using default lat and lon values instead of waiting for the user's location. How can I fix the code so that I can get desired output?
I'm new to JS and SO, so if any clarification is needed let me know. By the way I'm also sharing the code for better understanding. Sorry for such a long post :(
const WEATHER_API_KEY = "f19d6e315954bfb123e794ab55aa28c4";
const state = {
location: {
//setting default location of paris
lat: 48.8566969,
lng: 2.3514616
}
};
///////////////////////////////////////
// Geolocation api function
const options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
};
// Getting location using geolocation API
const getPosition = function () {
return new Promise(function (resolve, reject) {
navigator.geolocation.getCurrentPosition(resolve, reject, options);
});
};
//////////////////////////////////////////////
// Helper function to fetch data from api
const TIMEOUT_SEC = 5;
const timeout = function (s) {
return new Promise(function (_, reject) {
setTimeout(function () {
reject(new Error(`Request took too long! Timeout after ${s} second`));
}, s * 1000);
});
};
//get json data from api
export const AJAX = async function (url, method = undefined) {
try {
const fetchPro = method
? fetch(url, {
method: "get"
})
: fetch(url);
const res = await Promise.race([fetchPro, timeout(TIMEOUT_SEC)]);
const data = await res.json();
if (!res.ok) throw new Error(`${data.message} (${res.status})`);
return data;
} catch (err) {
throw err;
}
};
//////////////////////////////
// Executing functions and fetching data
const loadData = async function () {
try {
const { coords } = await getPosition();
const { latitude, longitude } = coords;
state.location.lat = latitude;
state.location.lng = longitude;
const weatherData = await AJAX(
`https://api.openweathermap.org/data/2.5/onecall?lat=${state.location.lat}&lon=${state.location.lng}&&units=metric&appid=${WEATHER_API_KEY}`
);
console.log(weatherData);
} catch (err) {
console.error("Error occured!!", err);
}
};
window.addEventListener("load", loadData);