如何使用异步?

How to use async?

我正在做一个 for 循环来检查一些值,这里是一个简短的版本。我不明白的是为什么 console.log(indirizzo[a]); 给出 undefined 而如果我这样做 console.log(indirizzo); 我得到所有值

  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]);
      }
    }
  }

我这样做的结果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"

我这样做的结果console.log(indirizzo[a]);

undefined

我知道地理编码器与 per the docs 一样是异步的,但我对在我的案例中将回调放在何处感到很困惑。

来自 [Mark Meyer][1] 回复:

您的主要问题是 geocoder.geocode() 是异步的并且需要回调。您正在将一个函数传递给回调,但将 return 值视为它将 return 来自主函数 findLatLang(),但它不会。目前 findLatLang() return 什么都没有。

findLatLang() 是你应该得到承诺的地方,return 它来自函数:

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));
            }
    })
    })
} 

然后在 getPoints() 的循环中,您可以将这些承诺收集到一个数组中,然后在数组上调用 Promise.all(),一旦所有承诺都已解决,该数组将为您提供值:

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);
})

Promise.all() 方法 return 是一个单一的 Promise,当所有作为可迭代对象传递的 promises 都已实现或当 iterable 不包含任何 promises 或当 iterable 包含已被传递的 promises 时,它会实现returned.

已兑现和未兑现的承诺

不清楚 addressData 的来源 - 您在函数中使用它,但它没有被传递到任何地方。

查看 [Mark Meyer][1] 的概念证明:

proof of concept fiddle

代码片段:

(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);