How to use async?

為{幸葍}努か 提交于 2021-02-05 11:11:18

问题


I'm doing a for loop to check against some values, on here is a short version. What I don't understand is why console.log(indirizzo[a]); is giving undefined while if I do console.log(indirizzo); I get all values

  var indirizzo = [];

  for (var i = 0; i < savedRepods.length; i++) {
    for (var a = 0; a < ids.length; a++) {
      if(savedRepods[i] == ids[a]) {
        var geocoder = new google.maps.Geocoder;
        var latlngStr = coords[a].split(',', 2);
        var latlng = {lat: parseFloat(latlngStr[0]), lng: parseFloat(latlngStr[1])};
        geocoder.geocode({'location': latlng}, function(results, status) {
          indirizzo.push(results[0].formatted_address);
        });
        console.log(indirizzo[a]);
      }
    }
  }

result if I do console.log(indirizzo);

0: "Corso Vittorio Emanuele, 1, 09017 Sant'Antioco SU, Italia"
1: "Via Nazionale, 78, 09017 Sant'Antioco SU, Italia"
2: "Via Giosuè Carducci, 15, 09017 Sant'Antioco SU, Italia"
3: "Via Perret, 11, 09017 Sant'Antioco SU, Italia"
4: "Lungomare Amerigo Vespucci, 2A, 09017 Sant'Antioco SU, Italia"

result if I do console.log(indirizzo[a]);

undefined

I know the geocoder is asynchronous as per the docs but I'm having a lot of confusion on where to place the callback on my case.


回答1:


From [Mark Meyer][1] Response:

Your main issue is that geocoder.geocode() is asynchronous and takes a callback. You are passing a function to the callback but treating the return value as if it will return from the main function, findLatLang(), but it won't. Currently findLatLang() returns nothing.

findLatLang() is where you should have the promise and return it from the function:

function findLatLang(address, geocoder, mainMap) {
    return new Promise(function(resolve, reject) {
        geocoder.geocode({'location': address}, function(results, status) {
            if (status === 'OK') {
                console.log(results);
                resolve([results[0].geometry.location.lat(), results[0].geometry.location.lng()]);
            } else {
                reject(new Error('Couldnt\'t find the location ' + address));
            }
    })
    })
} 

Then in the loop in getPoints() you can just collect those promises into an array and call Promise.all() on the array which will give you the values once all promises have resolved:

function getPoints(geocoder,map) {
    let locationData = [];
    var indirizzo = [];
    for (var i = 0; i < savedRepods.length; i++) {
        for (var a = 0; a < ids.length; a++) {
            if(savedRepods[i] == ids[a]) {
                var geocoder = new google.maps.Geocoder;
                var latlngStr = coords[a].split(',', 2);
                var latlng = {lat: parseFloat(latlngStr[0]), lng: parseFloat(latlngStr[1])};
                locationData.push(findLatLang(latlng, geocoder, map))
                console.log(indirizzo[a]);
            }
        }
    }
    return locationData // array of promises
}

var locations = getPoints(geocoder,map)

Promise.all(locations)     
.then(function(returnVals){
        // you should have return values here when
        // all promises have rsolved
          console.log(returnVals);
})

The Promise.all() method returns a single Promise that fulfills when all of the promises passed as an iterable have been fulfilled or when the iterable contains no promises or when the iterable contains promises that have been fulfilled and non-promises that have been returned.

It's not clear where addressData is coming from - you are using it in the function, but it's not being passed in anywhere.

View proof of concept of [Mark Meyer][1] Response:

proof of concept fiddle

code snippet:

(function($) {

    var savedRepods = <?php echo json_encode($userPostsInternal); ?>;
    savedRepods = savedRepods.split(",");

    var date = [],
        coords = [],
        ids = [],
        metal = [],
        plastic = [],
        paper = [],
        glass = [],
        indirizzo = [];

    var array = <?php echo $contents; ?>;

    array.map(function(item) {
        coords.push(item.Lat + "," + item.Lng);
        ids.push(item.ID);
        date.push(item.Date);
        plastic.push(item.Plastic);
        paper.push(item.Paper);
        glass.push(item.Glass);
        metal.push(item.Metal);
    });

    /**
    * findLatLang
    */
    function findLatLang(location, geocoder, value) {
        /**
        * Return new Promise what resolves when
        * the geocoder is successfull
        * and push in the array of promises
        */
        return new Promise(function(resolve, reject) {
            /** Do geocoder */
            geocoder.geocode({
                'location': location
            }, function(results, status) {
                /**
                * If geocoder is Ok
                */
                if (status === 'OK') {
                    /**
                    * When the geocoder is successfull located
                    * resolve the promise and send the response of formate address
                    */
                    resolve([results[0].formatted_address, value]);
                } else {
                    /**
                    * Reject the promise
                    */
                    reject(new Error('Couldnt\'t find the location ' + location));
                }
            })
        })
    }

    /**
    * processData
    * return an array of promises
    */
    function getPoints() {
        /**
        * Declare a variable of promises that have a geocoder
        */
        let locationData = [];
        for (var i = 0; i < savedRepods.length; i++) {
            for (var a = 0; a < ids.length; a++) {
                if (savedRepods[i] == ids[a]) {
                    var geocoder = new google.maps.Geocoder;
                    var latlngStr = coords[a].split(',', 2);
                    var latlng = {
                        lat: parseFloat(latlngStr[0]),
                        lng: parseFloat(latlngStr[1])
                    };

                    /**
                    * Push geocoder in array of locationdata
                    * Send the geocoder object on function and send the map
                    */
                    locationData.push(findLatLang(latlng, geocoder, a))
                }
            }
        }

        /** return array of promises */
        return locationData;
    }

    /**
    * Now process the response from locationData
    */
    var locations = getPoints();

    /**
    * Promise all
    * freecodecamp.org/news/…
    * The Promise.all() method returns a single Promise that fulfills when all of the promises
    * passed as an iterable have been fulfilled or when the iterable contains no promises or when
    * the iterable contains promises that have been fulfilled and non-promises that have been returned.
    * It rejects with the reason of the first promise that rejects, or with the error caught by the
    * first argument if that argument has caught an error inside it using try/catch/throw blocks.
    * ONLY RETURN VALUE WHEN ALL PROMISES HAS ENDED
    * @TODO => SHOW LOADER IN PROCESS
    */

    Promise.all(locations)
        .then(function(returnVals) {
            console.warn(returnVals)
            _indirizzo = returnVals;
            doAddress(_indirizzo)
        });

    function doAddress(_indirizzo) {
        _indirizzo.forEach(function(item) {
            var a = item[1];
            var location = item[0];
            $("#eachValue ul").append("<li class='list-group-item'>repod id= " + ids[a] + "<br> Indirizzo = " + location + "<br> Metallo = " + metal[a] + ", <br> Plastica = " + plastic[a] + ", <br> Vetro = " + glass[a] + ", <br> Carta = " + paper[a] + "</li>");
        })
    }

})(jQuery);


来源:https://stackoverflow.com/questions/60480802/how-to-use-async

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!