繁体   English   中英

如何在Javascript事件被触发一次然后在一段时间内不再被触发时如何响应?

[英]How to respond to a Javascript event only if it is fired once and then not fired again during some time period?

在我的应用程序中,我会听取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实现这一点,但没有成功。

任何想法将不胜感激:)

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

例如。

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

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)

谷歌建议使用另一个听众...

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

引用“请注意,您可以侦听bounds_changed事件,但它会在用户平移时持续触发;相反,一旦用户停止平移/缩放,就会触发空闲。” /引用

看到

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

此代码将确保自事件最后一次触发以来已经过了半秒(在评论TODO )。 我想这就是你想要的。

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

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

一个快速而肮脏的解决方案是减少频繁调用服务器:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM