Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is function in then not receiving object

Tags:

javascript

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.

like image 425
matua Avatar asked Nov 21 '25 12:11

matua


1 Answers

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);
    }
}
like image 198
Jamiec Avatar answered Nov 23 '25 01:11

Jamiec