Google Maps API v3 中的 OVER_QUERY_LIMIT:如何在 Javascript 中暂停/延迟以减慢速度?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11792916/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 07:06:59  来源:igfitidea点击:

OVER_QUERY_LIMIT in Google Maps API v3: How do I pause/delay in Javascript to slow it down?

javascriptgoogle-maps-api-3

提问by user1573571

I'm hitting an issue that is WELL discussed in these forums, but none of the recommendations seem to be working for me so I'm looking for some full javascript that works when saved as an html file.

我遇到了一个在这些论坛中讨论得很好的问题,但似乎没有任何建议对我有用,所以我正在寻找一些完整的 javascript,它可以在保存为 html 文件时工作。

The issue is I keep hitting the OVER_QUERY_LIMIT error when trying to geocode > 11 locations on a Google Map using the V3 APIs called by Javascript. I understand that there is a limit to the rate at which you can call the geocoder (as well as the daily limit on total volume), so I need to introduce a pause in between each result in the array.

问题是当我尝试使用 Javascript 调用的 V3 API 在 Google 地图上对 > 11 个位置进行地理编码时,我一直遇到 OVER_QUERY_LIMIT 错误。我知道您可以调用地理编码器的速率有限制(以及总体积的每日限制),因此我需要在数组中的每个结果之间引入暂停。

Any help very much appreciated.

非常感谢任何帮助。

Here is my code:

这是我的代码:

<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
var geocoder;
var map;
var wait = false;


  function initialize() {
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(51.32, 0.5);



var myOptions = {
  zoom: 8,
  center: latlng,
  mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
codeAddress('KT16 8LA' + ', UK');
codeAddress('LS8 2LQ' + ', UK');
codeAddress('NE13 8AF' + ', UK');
codeAddress('KT12 2BE' + ', UK');
codeAddress('W1W 8AN' + ', UK');
codeAddress('EC3N 2LS' + ', UK');
codeAddress('BS9 3BH' + ', UK');
codeAddress('KA10 6LZ' + ', UK');
codeAddress('EC1V 9BW' + ', UK');
codeAddress('WD18 8YN' + ', UK');
codeAddress('HA3 6DQ' + ', UK');
codeAddress('W1U 3PL' + ', UK');
codeAddress('W1T 7QL' + ', UK');
codeAddress('W1S 1TD' + ', UK');
codeAddress('SW1X 8NX' + ', UK');
codeAddress('LE2 8ET' + ', UK');
codeAddress('BA3 4BH' + ', UK');
codeAddress('AL3 8JP' + ', UK');
codeAddress('DE55 4QJ' + ', UK');
codeAddress('W6 0QT' + ', UK');
codeAddress('LA1 1PP' + ', UK');
codeAddress('SW16 4DH' + ', UK');
codeAddress('WC2N 6DF' + ', UK');
codeAddress('RM6 6LS' + ', UK');
codeAddress('S25 3QZ' + ', UK');
codeAddress('WC2H 7LR' + ', UK');
codeAddress('BH24 1DW' + ', UK');
codeAddress('EC2N 6AR' + ', UK');
codeAddress('W1U 2FA' + ', UK');
codeAddress('B60 3DX' + ', UK');    
}

  function codeAddress(vPostCode) {
if (geocoder) {
  geocoder.geocode( { 'address': "'" + vPostCode + "'"}, function(results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
      map.setCenter(results[0].geometry.location);
      var marker = new google.maps.Marker({
          map: map, 
          position: results[0].geometry.location
      });
    } else {
      alert("Geocode was not successful for the following reason: " + status);
    }
  });
}
}

</script>
<body style="margin:0px; padding:0px;" onload="initialize()">
<div id="map_canvas" style="width:100%; height:90%"></div>
</body>

EDIT: This is what I've tried to do to get it to pause/wait in the relevant section, but it doesn't do anything:

编辑:这是我试图让它在相关部分暂停/等待的方法,但它没有做任何事情:

function codeAddress(vPostCode) {
    if (geocoder) {
    while (wait) { /* Just wait. */ };
      geocoder.geocode( { 'address': "'" + vPostCode + "'"}, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          map.setCenter(results[0].geometry.location);
          var marker = new google.maps.Marker({
              map: map, 
              position: results[0].geometry.location
          });
        /* When geocoding "fails", see if it was because of over quota error: */
        } else if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) { 
        wait = true;
        setTimeout("wait = true", 2000);
        //alert("OQL: " + status);
        } else {
          alert("Geocode was not successful for the following reason: " + status);
        }
      });
    }
  }

回答by Andrew Leach

Nothing like these two lines appears in Mike Williams' tutorial:

Mike Williams 的教程中没有出现像这两行这样的内容:

    wait = true;
    setTimeout("wait = true", 2000);

Here's a Version 3 port:

这是第 3 版端口:

http://acleach.me.uk/gmaps/v3/plotaddresses.htm

http://acleach.me.uk/gmaps/v3/plotaddresses.htm

The relevant bit of code is

相关的代码位是

  // ====== Geocoding ======
  function getAddress(search, next) {
    geo.geocode({address:search}, function (results,status)
      { 
        // If that was successful
        if (status == google.maps.GeocoderStatus.OK) {
          // Lets assume that the first marker is the one we want
          var p = results[0].geometry.location;
          var lat=p.lat();
          var lng=p.lng();
          // Output the data
            var msg = 'address="' + search + '" lat=' +lat+ ' lng=' +lng+ '(delay='+delay+'ms)<br>';
            document.getElementById("messages").innerHTML += msg;
          // Create a marker
          createMarker(search,lat,lng);
        }
        // ====== Decode the error status ======
        else {
          // === if we were sending the requests to fast, try this one again and increase the delay
          if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
            nextAddress--;
            delay++;
          } else {
            var reason="Code "+status;
            var msg = 'address="' + search + '" error=' +reason+ '(delay='+delay+'ms)<br>';
            document.getElementById("messages").innerHTML += msg;
          }   
        }
        next();
      }
    );
  }

回答by geocodezip

The general answer to this question is:

这个问题的一般答案是:

Don't geocode known locations every time you load your page. Geocode them off-line and use the resulting coordinates to display the markers on your page.

不要在每次加载页面时对已知位置进行地理编码。离线对它们进行地理编码,并使用生成的坐标在您的页面上显示标记。

The limits exist for a reason.

存在限制是有原因的。

If you can't geocode the locations off-line, see this page (Part 17 Geocoding multiple addresses)from Mike Williams' v2 tutorial which describes an approach, port that to the v3 API.

如果您无法离线对位置进行地理编码,请参阅Mike Williams 的 v2 教程中的此页面(第 17 部分对多个地址进行地理编码),其中介绍了一种将其移植到 v3 API 的方法。

回答by sachin gavas

Here I have loaded 2200 markers. It takes around 1 min to add 2200 locations. https://jsfiddle.net/suchg/qm1pqunz/11/

这里我加载了 2200 个标记。添加 2200 个位置大约需要 1 分钟。 https://jsfiddle.net/suchg/qm1pqunz/11/

//function to get random element from an array
    (function($) {
        $.rand = function(arg) {
            if ($.isArray(arg)) {
                return arg[$.rand(arg.length)];
            } else if (typeof arg === "number") {
                return Math.floor(Math.random() * arg);
            } else {
                return 4;  // chosen by fair dice roll
            }
        };
    })(jQuery);

//start code on document ready
$(document).ready(function () {
    var map;
    var elevator;
    var myOptions = {
        zoom: 0,
        center: new google.maps.LatLng(35.392738, -100.019531), 
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    map = new google.maps.Map($('#map_canvas')[0], myOptions);

    //get place from inputfile.js
    var placesObject = place;
    errorArray = [];

  //will fire 20 ajax request at a time and other will keep in queue
    var queuCounter = 0, setLimit = 20; 

  //keep count of added markers and update at top
  totalAddedMarkers = 0;

  //make an array of geocode keys to avoid the overlimit error
    var geoCodKeys = [
                    'AIzaSyCF82XXUtT0vzMTcEPpTXvKQPr1keMNr_4',
                    'AIzaSyAYPw6oFHktAMhQqp34PptnkDEdmXwC3s0',
                    'AIzaSyAwd0OLvubYtKkEWwMe4Fe0DQpauX0pzlk',
                    'AIzaSyDF3F09RkYcibDuTFaINrWFBOG7ilCsVL0',
                    'AIzaSyC1dyD2kzPmZPmM4-oGYnIH_0x--0hVSY8'                   
                ];

  //funciton to add marker
    var addMarkers = function(address, queKey){
        var key = jQuery.rand(geoCodKeys);
        var url = 'https://maps.googleapis.com/maps/api/geocode/json?key='+key+'&address='+address+'&sensor=false';

        var qyName = '';
        if( queKey ) {
            qyName = queKey;
        } else {
            qyName = 'MyQueue'+queuCounter;
        }

        $.ajaxq (qyName, {
            url: url,
            dataType: 'json'
        }).done(function( data ) {
                    var address = getParameterByName('address', this.url);
                    var index = errorArray.indexOf(address);
                    try{
                        var p = data.results[0].geometry.location;
                        var latlng = new google.maps.LatLng(p.lat, p.lng);
                        new google.maps.Marker({
                            position: latlng,
                            map: map
                        });
                        totalAddedMarkers ++;

            //update adde marker count
                        $("#totalAddedMarker").text(totalAddedMarkers);
                        if (index > -1) {
                            errorArray.splice(index, 1);
                        }
                    }catch(e){
                        if(data.status = 'ZERO_RESULTS')
                            return false;

            //on error call add marker function for same address
            //and keep in Error ajax queue
                        addMarkers( address, 'Errror' );
                        if (index == -1) {
                            errorArray.push( address );
                        }
                    }
        });

    //mentain ajax queue set
        queuCounter++;
        if( queuCounter == setLimit ){
            queuCounter = 0;
        }
    }

  //function get url parameter from url string
    getParameterByName = function ( name,href )
    {
      name = name.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]");
      var regexS = "[\?&]"+name+"=([^&#]*)";
      var regex = new RegExp( regexS );
      var results = regex.exec( href );
      if( results == null )
        return "";
      else
        return decodeURIComponent(results[1].replace(/\+/g, " "));
    }

  //call add marker function for each address mention in inputfile.js
    for (var x = 0; x < placesObject.length; x++) {
        var address = placesObject[x]['City'] + ', ' + placesObject[x]['State'];
        addMarkers(address);
    }
});

回答by Ronen

Using "setInterval" & "clearInterval" fixes the problem:

使用“setInterval”和“clearInterval”解决了这个问题:

function drawMarkers(map, markers) {
    var _this = this,
        geocoder = new google.maps.Geocoder(),
        geocode_filetrs;

    _this.key = 0;

    _this.interval = setInterval(function() {
        _this.markerData = markers[_this.key];

        geocoder.geocode({ address: _this.markerData.address }, yourCallback(_this.markerData));

        _this.key++;

        if ( ! markers[_this.key]) {
            clearInterval(_this.interval);
        }

    }, 300);
}

回答by Leandro Curbelo

this post was made a while ago, but it provides an answer that did not solve the problem regarding reaching the limit of requests in an iteration for me, so I publish this, to help who else has not served.

这篇文章是前一段时间发布的,但它提供的答案并没有解决我在迭代中达到请求限制的问题,所以我发布了这篇文章,以帮助其他没有服务的人。

My environment happened in Ionic 3.

我的环境发生在 Ionic 3 中。

Instead of making a "pause" in the iteration, I ocurred the idea of ??iterating with a timer, this timer has the particularity of executing the code that would go in the iteration, but will run every so often until it is reached the maximum count of the "Array" in which we want to iterate.

我没有在迭代中“暂停”,而是产生了用 a 迭代的想法timer,这个计时器具有执行迭代中的代码的特殊性,但会每隔一段时间运行一次,直到达到最大值我们要迭代的“数组”的计数。

In other words, we will consult the Google API in a certain time so that it does not exceed the limit allowed in milliseconds.

换句话说,我们会在一定时间内咨询 Google API,使其不超过允许的毫秒限制。

// Code to start the timer
    this.count= 0;
    let loading = this.loadingCtrl.create({
      content: 'Buscando los mejores servicios...'
    });
    loading.present();
    this.interval = setInterval(() => this.getDistancias(loading), 40);
// Function that runs the timer, that is, query Google API
  getDistancias(loading){
    if(this.count>= this.datos.length){
      clearInterval(this.interval);
    } else {
      var sucursal = this.datos[this.count];
      this.calcularDistancia(this.posicion, new LatLng(parseFloat(sucursal.position.latitude),parseFloat(sucursal.position.longitude)),sucursal.codigo).then(distancia => {
    }).catch(error => {
      console.log('error');
      console.log(error);
    });
    }
    this.count += 1;
  }
  calcularDistancia(miPosicion, markerPosicion, codigo){
    return new Promise(async (resolve,reject) => {
      var service = new google.maps.DistanceMatrixService;
      var distance;
      var duration;
      service.getDistanceMatrix({
        origins: [miPosicion, 'salida'],
        destinations: [markerPosicion, 'llegada'],
        travelMode: 'DRIVING',
        unitSystem: google.maps.UnitSystem.METRIC,
        avoidHighways: false,
        avoidTolls: false
      }, function(response, status){
        if (status == 'OK') {
          var originList = response.originAddresses;
          var destinationList = response.destinationAddresses;
          try{
            if(response != null && response != undefined){
              distance = response.rows[0].elements[0].distance.value;
              duration = response.rows[0].elements[0].duration.text;
              resolve(distance);
            }
          }catch(error){
            console.log("ERROR GOOGLE");
            console.log(status);
          }
        }
      });
    });
  }

I hope this helps!

我希望这有帮助!

I'm sorry for my English, I hope it's not an inconvenience, I had to use the Google translator.

我很抱歉我的英语,我希望这不是一个不便,我不得不使用谷歌翻译。

Regards, Leandro.

问候,莱安德罗。

回答by Buksy

You are using setTimeoutwrong way. The (one of) function signature is setTimeout(callback, delay). So you can easily specify what code should be run after what delay.

你用setTimeout错了方法。(之一)函数签名是setTimeout(callback, delay). 所以你可以很容易地指定在什么延迟之后应该运行什么代码。

var codeAddress = (function() {
    var index = 0;
    var delay = 100;

    function GeocodeCallback(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            map.setCenter(results[0].geometry.location);
            new google.maps.Marker({ map: map, position: results[0].geometry.location, animation: google.maps.Animation.DROP });
            console.log(results);
        }
        else alert("Geocode was not successful for the following reason: " + status);
    };

    return function(vPostCode) {
        if (geocoder) setTimeout(geocoder.geocode.bind(geocoder, { 'address': "'" + vPostCode + "'"}, GeocodeCallback), index*delay);
        index++;
    };
})();

This way, every codeAddress()call will result in geocoder.geocode()being called 100ms later after previous call.

这样,每次codeAddress()调用都会在geocoder.geocode()上一次调用后 100 毫秒后被调用。

I also added animation to marker so you will have a nice animation effect with markers being added to map one after another. I'm not sure what is the current google limit, so you may need to increase the value of delayvariable.

我还为标记添加了动画,因此您将有一个很好的动画效果,标记被一个接一个地添加到地图上。我不确定当前的 google 限制是多少,因此您可能需要增加delay变量的值。

Also, if you are each time geocoding the same addresses, you should instead save the results of geocode to your db and next time just use those (so you will save some traffic and your application will be a little bit quicker)

此外,如果您每次都对相同的地址进行地理编码,您应该将地理编码的结果保存到您的数据库中,下次只需使用这些结果(这样您就可以节省一些流量并且您的应用程序会更快一些)