简体   繁体   中英

Google is not defined when callback function called

function initMap() {

            var map = new google.maps.Map(document.getElementById('map'), {
              ..........
            var markers = locations.map(function(location, i) {
              return new google.maps.Marker({
                position: location,
                label: labels[i % labels.length]
              });
            });

            // Add a marker clusterer to manage the markers.
            var markerCluster = new MarkerClusterer(map, markers,
                {imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'});
        }


 //Store LatLng of PostalCode
    var locations = [];

function getLatLng(zipcode, callback) 
{
    var geocoder = new google.maps.Geocoder();
    var address = zipcode;
    geocoder.geocode({ 'address': address }, function (results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            var latitude = results[0].geometry.location.lat();
            var longitude = results[0].geometry.location.lng();
            callback({lat: latitude, lng: longitude });
        } else {
            alert("Request failed.")
        }
    });
}

function getpc(postalcode) {

    getLatLng(postalcode, function (data) {
        locations.push({
            lat : data.lat,
            lng : data.lng
        });
        console.log("lat = " + data.lat + " and lng = " + data.lng);
    });   

}

getpc("640632");

When i tried to call the function getpc(), it returned google is not defined. However, if i tried to remove it, the error does not occur. I search up numerous methods to solve this but none worked. Appreciate any help.

This is the error showed on console.log :

Uncaught ReferenceError: google is not defined
    at getLatLng (GoogleMapTest.aspx:73)
    at getpc (GoogleMapTest.aspx:88)
    at GoogleMapTest.aspx:98

Your ReferenceError (variable not found in heap or stack) is likely due to the fact that your google maps api has not finished downloading and/or parsed yet by your webpage.

There are many benefits to loading external resources asynchronously however dependency issues like the one you're having are common.

Without knowing what your end product is you have a few options:

  1. Synchronously load the maps api, thus ensuring when you invoke getpc() you can reliably assume the google object will be in the heap. Change <script src="maps.googleapis.com/maps/api/…" async defer> </script> to <script src="maps.googleapis.com/maps/api/…"> </script> . The Google docs suggest removing async and defer for for these reasons exactly

In the script tag that loads the Maps JavaScript API, it is possible to omit the async attribute and the callback parameter. This will cause the loading of the API to block until the API is downloaded.

This will probably slow your page load. But it means you can write subsequent script tags assuming that the API is already loaded.

  1. Keep async and defer attributes in the script tag, but instead of invoking getpc from your own script, supply it as the callback argument in the query param like so: src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=getpc">. If you need to invoke 2 or more functions after the maps api is loaded you could compose these into one src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=getpc">. If you need to invoke 2 or more functions after the maps api is loaded you could compose these into one

  2. Manually download the library using XMLHttpRequest and perform any subsequent routines by supplying a callback to the XMLHttpRequest.onreadystatechange method. MDN handling onreadystatechange

  3. (Not Recommended) replace getpc("640632") with setTimeout(getpc.bind(null, '640632'), 4000)

UPDATE: It sounds like you need these routines to be ordered in such that getpc is invoked before initMap . To do this, you can you use the solution #3. Below is an example of how this would work:

let compose = function(fns) {
  return function() {
    while(fns.length) {
      fns.shift()();
    }
  }
};


let initmap = function() {
  console.log('Init Map');
};


let getpc = function(postalCode) {
  console.log(postalCode);
};


// pass an array of functions you want to be invoked in consecutive order
let initializationRoutines = compose([getpc.bind(null, '123'), initmap]); 

// invoke the functions one-by-one like so
initializationRoutines();

// Instead of invoking initializationRoutines, supply that as the callback to the // maps api. 
// ex: 
<script src="https://maps.googleapis.com/maps/api/jskey=YOUR_API_KEY&callback=initializationRoutines"></script>

One last note, if you use this solution you will need to define initializationRoutines before you insert the script tag that loads the maps api like so.

<head>
<script>
// Compose and define your functions HERE.... Before you load the map api
let compose = function(fns) {/** ... **/};
let initmap = function() {/** .... **/};
let getpc = function(postalCode) {/** .... **/};

// pass an array of functions you want to be invoked in consecutive order
let initializationRoutines = compose(/** ARRAY_OF_FUNCTIONS**/); 
</script>
<script src="https://maps.googleapis.com/maps/api/jskey=YOUR_API_KEY&callback=initializationRoutines"></script>
</head>
<body>
</body>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM