【问题标题】:OVER_QUERY_LIMIT in Google Maps API v3: How do I pause/delay in Javascript to slow it down?Google Maps API v3 中的 OVER_QUERY_LIMIT:如何在 Javascript 中暂停/延迟以减慢速度?
【发布时间】:2012-08-01 08:04:39
【问题描述】:

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

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

非常感谢任何帮助。

这是我的代码:

<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>

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

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

【问题讨论】:

标签: javascript google-maps-api-3


【解决方案1】:

Mike Williams 的教程中没有类似这两行的内容:

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

这是一个版本 3 的端口:

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

相关的代码是

  // ====== 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();
      }
    );
  }

【讨论】:

  • 也适用于路由,当批处理只是在增加延迟后递归到对 Google 的批处理调用。
  • 这是什么..@Andrew Leach 你能告诉我这些延迟和下一个地址是什么吗..你能解决这个问题吗Fiddle
  • delay 是以毫秒为单位的延迟; nextAddress 是地址计数器:如果地址失败,取消设置增量并增加延迟,以便再次尝试。完整的实现在我的网站上给出的链接:你的小提琴中没有这样的代码。
  • 第一个结果后是否可以设置地图中心?
  • @PaulLeclerc 我的示例仍然适用于我,尽管地理编码器已更改,因此实际找到的地址更少。如果您使用共享 IP 地址,则查询限制在该 IP 地址上的所有用户之间共享。这意味着移动网络的用户在开始之前可能会违反限制。
【解决方案2】:

这个问题的一般答案是:

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

限制的存在是有原因的。

如果您无法离线对位置进行地理编码,请参阅 Mike Williams 的 v2 教程中的 this page (Part 17 Geocoding multiple addresses),该教程描述了一种方法,将其移植到 v3 API。

【讨论】:

  • 感谢您的回复。我无法对它们进行离线地理编码,但您引用的页面没有提供任何我可以应用的示例。我真正需要的只是一个可以工作的延迟/暂停步骤。
  • 你看到了吗:view-source:econym.org.uk/gmap/example_geomulti.htm,它是为 v2 API 编写的,但这个概念应该适用于 v3 API。
  • 已经尝试过这个概念,但没有成功。它可能在 V2 和 V3 中运行良好,但我无法让它成功应用于上述 Javascript。
  • 您可以发布一个指向您的地图(或 jsfiddle)的链接,您试图让它工作但失败了,也许有人可以看到您哪里出错了。
  • 是的,根据上面的代码,它适用于前 80 次页面浏览量,然后使用免费使用中断。 3300 页面浏览量,如果您付费的话。
【解决方案3】:

我在这里加载了 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);
    }
});

【讨论】:

  • ToS 有一些您应该注意的限制:“不得使用超出交易限制和使用政策。如果您的 Maps API 实施产生大量交易,Google 保留设置交易限制的权利。 Google 还保留不时在文档中设置其他使用政策的权利。如果您想在这些交易限制或使用政策之外进行使用,您可以通过 Maps API 标准定价计划购买更多使用容量,或者您可以请联系 Google 地图销售团队,了解满足您需求的许可选项。”
  • @sachingavas 我收到 name.replace 不是函数错误消息
【解决方案4】:

使用“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);
}

【讨论】:

    【解决方案5】:

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

    我的环境发生在 Ionic 3 中。

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

    也就是说,我们会在一定的时间内查询 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);
              }
            }
          });
        });
      }
    

    我希望这会有所帮助!

    对不起,我的英语不好,希望不是不便,我不得不使用谷歌翻译。

    问候,莱安德罗。

    【讨论】:

      【解决方案6】:

      您以错误的方式使用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++;
          };
      })();
      

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

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

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

      【讨论】:

      • 如何将这段代码实现到我的代码中? jsfiddle.net/395rdhd8我尝试了很多东西,但没有任何运气。 STATUS OVER_QUERY_LIMIT 在我的控制台中出现在我的 STATUS.OK 之前。但为什么?谢谢。
      • 你的setTimeout用法不对,setTimeout不是让javascript休眠X秒,它是用来在X秒后运行指定函数
      • 我该如何解决? Javascript 不是我最强的技能。谢谢!
      • 其中一个选项是创建递归函数,如果请求不成功,该函数将调用自身,如下所示:jsfiddle.net/395rdhd8/1
      猜你喜欢
      • 2013-11-17
      • 1970-01-01
      • 1970-01-01
      • 2012-01-24
      • 1970-01-01
      相关资源
      最近更新 更多