【问题标题】:How to use async?如何使用异步?
【发布时间】:2020-06-14 06:34:58
【问题描述】:

我正在做一个 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 是异步的,但我对在我的案例中放置回调的位置有很多困惑。

【问题讨论】:

标签: javascript jquery geocoding


【解决方案1】:

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

您的主要问题是geocoder.geocode() 是异步的并且需要回调。您将一个函数传递给回调,但将返回值视为将从主函数findLatLang() 返回,但它不会。目前findLatLang() 不返回任何内容。

findLatLang() 是你应该拥有承诺并从函数中返回的地方:

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 收集到一个数组中,并在数组上调用Promise.all(),一旦所有promise 都解决了,它将为您提供值:

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() 方法返回一个 Promise,当所有作为 iterable 传递的 Promise 都已完成时,或者当 iterable 不包含 Promise 时,或者当 iterable 包含已完成的 Promise 和已完成的非 Promise 时,该 Promise 完成返回。

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

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

proof of concept fiddle

代码 sn-p:

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

【讨论】:

    猜你喜欢
    • 2012-01-20
    • 2017-09-03
    • 2020-05-28
    • 2020-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-10
    相关资源
    最近更新 更多