2010-07-15 64 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

相關問題