在我的应用程序中,我会收听Google Maps API的'bounds_changed'事件,以根据地图的新边界发送ajax请求来更新网页上的某些div:
google.maps.event.addListener(map, 'bounds_changed', function() {
// here goes an ajax call
}
当用户拖动地图时,会以高频率触发事件'bounds_changed'。太多了,发送到服务器的ajax请求太多了。
基本上我想在用户停止在一段时间内移动地图(例如500ms)之后才进行ajax调用。我对Javascript没有很多经验,并尝试使用setTimeout和clearTimeout来实现这一点,但没有成功。
任何想法都将被赞赏:)
答案 0 :(得分: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);
}
}()));
答案 1 :(得分: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
,blog post上就会有一个独立的function debounce(func, threshold, execAsap)
。
答案 2 :(得分:4)
google.maps.event.addListener(map, 'idle', showMarkers);
报价 “请注意,您可以监听bounds_changed事件,但它会在用户平移时持续触发;相反,一旦用户停止平移/缩放,空闲将会触发。” /报价
见
http://code.google.com/apis/maps/articles/toomanymarkers.html#gridbasedclustering
答案 3 :(得分:2)
此代码将确保自事件上次触发之前已经过半秒(在评论TODO
之前)。我想这就是你想要的。
var mapMoveTimer;
google.maps.event.addListener(map, 'bounds_changed', function(){
clearTimeout(mapMoveTimer);
mapMoveTimer = setTimeout(function(){
// TODO: stuff with map
}, 500);
});
答案 4 :(得分:2)
这是Brenton Alker的代码,但已转入实用功能。
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
}));
答案 5 :(得分: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