2010-07-15 55 views
11

在我的应用我听谷歌地图API“的bounds_changed”事件发送Ajax请求取决于地图的新边界在网页上更新一些DIV:如何仅在一段时间内触发一个Javascript事件并在一段时间内没有再次触发Javascript事件?

google.maps.event.addListener(map, 'bounds_changed', function() { 
    // here goes an ajax call 
} 

事件“的bounds_changed”是当用户拖动地图时用高频率发射。太多,以致有太多的Ajax请求被发送到服务器。

基本上我只想在用户停止在某段时间(例如500ms)内移动地图后才能进行ajax调用。我对Javascript并不是非常有经验,并试图用setTimeout和clearTimeout来实现这一目标,但没有成功。

任何想法,将不胜感激:)

+0

感谢所有为你解答! – Florent2 2010-07-16 16:28:15

回答

12

添加超时,该事件触发后运行代码为500ms,每次事件触发清除超时,并创建一个新的。

例如。

google.maps.event.addListener(map, 'bounds_changed', (function() { 
    var timer; 
    return function() { 
     clearTimeout(timer); 
     timer = setTimeout(function() { 
      // here goes an ajax call 
     }, 500); 
    } 
}())); 
+0

+1,尽管你应该分开担忧并将功能作为实用程序提取出来。 – gradbot 2010-07-16 00:36:51

+0

非常漂亮的技巧(具有三重嵌套功能),但很难阅读并遵循代码的意图,因此,难以长期维护。 – gMale 2010-07-16 00:42:13

+0

没错,如果它要被使用多次,我可能会把这两个外层的图层按照gradbot的建议放到一个库中。那么这将是一个简单的函数,需要回调。 – 2010-07-16 01:11:45

0

一个快速和肮脏的解决办法是调用服务器那么频繁:

var requestCounter = 0; 
var frequency = 50; 

google.maps.event.addListener(map, 'bounds_changed', function() { 
    if((++requestCounter % frequency) == 0){ 
      // here goes an ajax call (also, optionally reset the counter here) 
    } 
}); 

另外,我已经做了类似的在那里我已经重置的东西定时器每当我“听到”用户。一旦计时器过期,它会调用我的动作。所以定时器不断尝试关闭,但如果用户做了一些事情,定时器将被重置。最终,用户停止移动足够长的时间以致计时器有机会触发它的事件。


编辑:
线沿线的:

google.maps.event.addListener(map, 'bounds_changed', userInput); 

function userInput() { 
    resetTimer(); 
} 

凡resetTimer()清除/启动的计时器。这看起来像这样:

var inputTimer = null; 
var timeLimit = 500; 

function resetTimer() { 
    if(inputTimer != null) clearInterval(inputTimer); 
    inputTimer = setTimeout('contactServer()', timeLimit); 
} 

function contactServer() { 
    // here goes an ajax call 
} 

我还没有测试,这个编译,但它应该给你的基本想法。此代码具有足够的模块化优势,只需进行少量编辑即可在其他许多语言中使用。我遵循ActionScript中的类似逻辑。此外,它非常容易阅读,按照逻辑进行并保持(6个月后,当你忘记你的代码如何工作)。

我希望以某种方式帮助,

--gMale

+0

javascript不会编译^^ – Marko 2010-07-16 01:14:24

+0

@Marko肯定是的,V8在chrome JITs的代码中。 '^。^' – gradbot 2010-07-16 01:18:24

2

此代码将确保它一直半秒,因为该事件是最后做它的事(的评论TODO)之前被解雇。我认为这是你想要的。

var mapMoveTimer; 
google.maps.event.addListener(map, 'bounds_changed', function(){ 
    clearTimeout(mapMoveTimer); 
    mapMoveTimer = setTimeout(function(){ 
    // TODO: stuff with map 
    }, 500); 
}); 
+0

可以工作,但使用全球 – gradbot 2010-07-16 00:34:38

+1

,只有在有可能另一个脚本创建了同名全局时才有意义。如果这是一个问题,整个事情可能会被封闭,但如果它只是一个网页脚本的一次性,它根本就不重要。 – 2010-07-16 01:09:47

4

有可用的一个非常好的方法上unscriptable.com

Function.prototype.debounce = function (threshold, execAsap) { 
    var func = this, // reference to original function 
     timeout; // handle to setTimeout async task (detection period) 
    // return the new debounced function which executes the original function 
    // only once until the detection period expires 
    return function debounced() { 
     var obj = this, // reference to original context object 
      args = arguments; // arguments at execution time 
     // this is the detection function. it will be executed if/when the 
     // threshold expires 
     function delayed() { 
      // if we're executing at the end of the detection period 
      if (!execAsap) 
       func.apply(obj, args); // execute now 
      // clear timeout handle 
      timeout = null; 
     }; 
     // stop any current detection period 
     if (timeout) 
      clearTimeout(timeout); 
     // otherwise, if we're not already waiting and we're executing at the 
     // beginning of the waiting period 
     else if (execAsap) 
      func.apply(obj, args); // execute now 
     // reset the waiting period 
     timeout = setTimeout(delayed, threshold || 100); 
    }; 
} 

这将让你做的事:

// call the function 200ms after the bounds_changed event last fired: 
google.maps.event.addListener(map, 'bounds_changed', (function() { 
    // here goes an ajax call 
}).debounce(200)); 

// call the function only once per 200ms: 
google.maps.event.addListener(map, 'bounds_changed', (function() { 
    // here goes an ajax call 
}).debounce(200,true)); 

如果你不希望其他人充实到Function.prototype有一个独立的function debounce(func, threshold, execAsap)可在blog post获得。

+0

+1,非常酷,它保留了对象引用并允许参数。 – gradbot 2010-07-16 01:15:05

2

这是布伦顿阿尔克尔的代码,但移到了效用函数中。

var frequencyReduce = function(delay, callback){ 
    var timer; 
    return function(){ 
     clearTimeout(timer); 
     timer = setTimeout(callback, delay); 
    }; 
}; 

google.maps.event.addListener(map, 'bounds_changed', frequencyReduce(500, function(){ 
    // here goes an ajax call 
})); 
+0

拯救生命。谢谢。 – mapr 2015-06-25 20:46:17

3

谷歌建议使用其它监听...

google.maps.event.addListener(map, 'idle', showMarkers); 

报价 “需要注意的是,你可以听bounds_changed事件,但它不断地激发作为用户锅;相反,空闲会触发一次用户已经停止平移/缩放。“ /报价

看到

http://code.google.com/apis/maps/articles/toomanymarkers.html#gridbasedclustering

+0

就像一个魅力......和你的0.5秒定时器一样的感觉 – camel 2011-05-24 23:08:07

相关问题