Why is function in then not receiving object
I understand the notion of Promises, but something seems not to be completely clear to me.
I have the following html:
<!DOCTYPE html> .......
<div id="map"></div>
<script
src="https://maps.googleapis.com/maps/api/js?key=GOOGLE_API&callback=initialize"
async></script>
</body>
</html>
<script src="js/currentRoute.js"></script>
I have the following JS code:
async function getCurrentUserCoordinates() {
console.log("Am getCurrentUserCoordinates")
const url = baseUrl + `/SOME_REST_API_URL`;
if (checkAdminOrTechRights(parseToken(getToken()))) {
await fetch(url, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Authorization': `Bearer ${getToken()}`
},
})
.then((response) =>
response
.json()
)
.then(terminals => {
let locations = [];
terminals.forEach(terminal => {
locations.push({
lat: terminal.latitude,
lng: terminal.longitude,
name: terminal.name,
location: terminal.location
})
})
console.log(locations) // ALL IS PRINTING OK HERE
return locations;
}).catch((err) => {
console.error(err);
})
}
}
function initMap(locations) {
console.log("Am initMap")
console.log("printing locations: " + locations) // I HAVE UNDEFINED HERE
const map = new google.maps.Map(document.getElementById("map"), {
zoom: 12,
center: {lat: 0.123123123123, lng: 0.123123123123},
});
const infoWindow = new google.maps.InfoWindow({
content: "",
disableAutoPan: true,
});
const markers = locations.map((terminal, i) => {
const label = `${terminal.name}, ${terminal.location}`;
const marker = new google.maps.Marker({
position: terminal,
label,
});
marker.addListener("click", () => {
infoWindow.setContent(label);
infoWindow.open(map, marker);
});
return marker;
});
new markerClusterer.MarkerClusterer({markers, map});
}
async function initialize() {
console.log("Am initialize")
getCurrentUserCoordinates()
.then(locations => initMap(locations))
.then(() => console.log("Am done"))
.catch((err) => {
console.error("ERROR!!! " + err);
})
}
I have the following logs:
Am initialize
currentRoute.js:2 Am getCurrentUserCoordinates
currentRoute.js:28 (26) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]0: {lat: 1.123123123, lng: 1.123123123, name: 'TERM-0001', location: 'LOCATION'}1: {lat: 1.123123123, lng: 1.123123123, name: 'TERM-0099', location: 'LOCATION'}2: ............ 25: {lat: 1.123123123, lng: 1.123123123, name: 'TERM-0023', location: 'LOCATION'}length: 26[[Prototype]]: Array(0)
currentRoute.js:37 Am initMap
currentRoute.js:38 printing locations: undefined
So in my view initMap() has to be called when the getCurrentUserCoordinates() returns the result (locations). Inside the functions am getting locations and as seen on the logs they are printed. But the locations are passed as undefined inside the initMap functions.
What am I not getting here?
Thank you.
The main problem with your code was that you were calling return
from inside a nested function within then
which you had assumed would return from the outer method getCurrentUserCoordinates
but that is not the case.
Your functionality can be hugely simplified by not mixing async/await with then
- the former is easier to manage. The code also benefits from replacing the clunky array + forEach
with a simple map
over the array.
async function getCurrentUserCoordinates() {
console.log("Am getCurrentUserCoordinates")
const url = baseUrl + `/SOME_REST_API_URL`;
if (checkAdminOrTechRights(parseToken(getToken()))) {
try{
const result = await fetch(url, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Authorization': `Bearer ${getToken()}`
},
});
const terminals = await result.json();
let locations = terminals.map( terminal => ({
lat: terminal.latitude,
lng: terminal.longitude,
name: terminal.name,
location: terminal.location
}))
console.log(locations) // ALL IS PRINTING OK HERE
return locations;
}
catch(err){
console.error(err);
}
}
}
* Note the return locations
in this code is now in the outer scope of the method itself, however as the method is async
it actually returns a Promise
so you must await it later on (see below). H/T @JeremyThille
The same is true later in your code
async function initialize() {
console.log("Am initialize")
try{
const currentUserCoords = await getCurrentUserCoordinates();
const locations = initMap(currentUserCoords);
console.log("Am done"))
}
catch(err){
console.error("ERROR!!! " + err);
}
}