How to force callback method to wait for Google Markers creation Code Answer

I am making an app using the Google maps library. My problem is either there is an unexplicable delay in creating the Markers or I have an asynchronous problem I cannot see.

Explanation : the code fetches Electric Charging Stations Location along a route between a start and an end points, creates Google markers for each station the fetch returns (in Json format) and pushes them in an array. Later it is supposed to calculate a route with stopovers using those markers (not included here).

The problem is it launches the calculation method before it finishes to create the markers.

In order to harmonize results I don’t fetch all results at once. Instead I made a loop that does the following :

  1. create a route and extract an encoded polyline from it (to be used in the URL)
  2. fetch results
  3. create markers, set them on map and pushes them on array
  4. logs in console the job is done (‘EV markers creation finished’)

Then it launches the route calculation process (here replaced by an alert ‘calculateAndDisplayRoute method called)

But in reality the loop finishes and logs in console but the last markers are not created, the alert is launched and only after can you see the markers appear on the map.

You can try the following code snippet :https://codepen.io/reivilo85k/pen/wvowpab

Here is the problematic code (I had to add more code in the codepen in order to make it work though) :

chargingPointsMarkers = [];
markerArray = [];

async callbackHandler(startEndPointsArray, calculateAndDisplayRoute): Promise<void> {
    await this.setChargingStationsMarkers();
    calculateAndDisplayRoute();
  }

function calculateAndDisplayRoute() {
      alert('calculateAndDisplayRoute method called')
    }

  async function setChargingStationsMarkers() {
const polylineMarkersArray = await createMarkersArray();
console.log('Polyline Markers created', polylineMarkersArray);

    const baseUrl = 'URL REMOVED';

    for (let j = 0; j < polylineMarkersArray.length - 1; j++) {
      const origin = polylineMarkersArray[j].getPosition();
      const destination = polylineMarkersArray[j + 1].getPosition();
      
      const route = await createRoute(origin, destination);
      const encodedPolyline = route.overview_polyline;
      const queryUrl = baseUrl + '&polyline='+ encodedPolyline + '&distance=50';

      await fetch(queryUrl)
        .then((response) => response.json())
        .then( async (data) => await createChargerPointMarkers(data))
        .then (() => {
                   const k = j + 1;
          const l = polylineMarkersArray.length - 1;
          if (j === polylineMarkersArray.length - 2) {
            console.log('loop ' + k + ' of ' + l);
            console.log('EV markers creation finished');
          }else{
            console.log('loop ' + k + ' of ' + l);
          }
        });
    }
}

async createChargerPointMarkers(jsonChargingPoints): Promise<void> {
    // Convert the Json response elements to Google Markers, places them on the Map and pushes them to an array.
    for (const item of jsonChargingPoints) {
      const LatLng = new google.maps.LatLng(parseFloat(item.AddressInfo.Latitude), parseFloat(item.AddressInfo.Longitude));
      const marker = await new google.maps.Marker({
        position: LatLng,
        map: this.map,
        draggable: false,
      });
      this.markerArray.push(marker);
      this.chargingPointsMarkers.push(marker);
    }
  }

  async createRoute(point1, point2): Promise<google.maps.DirectionsRoute> {
    // Returns a Google DirectionsRoute object
    const directionsService = new google.maps.DirectionsService();
    const request = {
      origin: point1,
      destination: point2,
      travelMode: google.maps.TravelMode.DRIVING,
      unitSystem: google.maps.UnitSystem.METRIC
    };
    return new Promise(resolve => directionsService.route(request,
      (result, status) => {
        if (status === 'OK') {
          resolve(result.routes[0]);
        } else {
          window.alert('Directions request failed due to ' + status);
        }
      })
    );
  }

Answer

As I mentioned in my comment your code works as expected and the issue comes from the use of alert() which at the time it is fired, blocks your browser from executing any further code — and more importantly — further UI rendering.

This is easily reproducible with almost any code that does something to the DOM.

const el = document.createElement("div");
const text = document.createTextNode("Hello world");

el.appendChild(text);
document.body.appendChild(el);

console.log('done');
alert('done');

The alert is fired after the node has been added to the DOM but before the browser has rendered it (at least in my browser).

Replacing the alert() in your code with a console.log() and adding another console.log('marker added') where you create each google.maps.Marker() shows that the order of events is what you expected:

  1. (84) marker added
  2. loop 6 of 6
  3. EV markers creation finished
  4. calculateAndDisplayRoute method called

but the alert() is fired before the browser has finished rendering the markers.

You should probably avoid using alert() for debugging purposes, or use it carefully as it can be misleading.

Related Posts

© No Copyrights, All Questions are retrived from public domain.
Tutorial Guruji