2010-07-15 3 views
11

In meiner Anwendung höre ich die Google Maps API ‚bounds_changed‘ Ereignis eine Ajax-Anfrage senden einige div auf der Webseite zu aktualisieren, je nach den neuen Grenzen der Karte:Wie reagiert man auf ein Javascript-Ereignis nur, wenn es einmal ausgelöst wird und dann während eines bestimmten Zeitraums nicht erneut ausgelöst wird?

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

Das Ereignis ‚bounds_changed‘ ist Wird mit hoher Frequenz ausgelöst, wenn der Benutzer die Karte zieht. So viel, dass zu viele Ajax-Anfragen an den Server gesendet werden.

Grundsätzlich möchte ich den Ajax-Aufruf nur machen, nachdem der Benutzer angehalten hat, die Karte während einiger Zeit (zum Beispiel 500ms) zu verschieben. Ich bin nicht sehr erfahren mit Javascript und versuchte dies mit setTimeout und clearTimeout zu erreichen, aber ohne Erfolg.

häufig Jede Idee würde geschätzt :)

+0

bedankt sich bei allen für Ihre Antworten! – Florent2

Antwort

12

ein Timeout hinzufügen, dass Ihr Code 500ms nach dem Ereignis wird ausgelöst, läuft jedes Mal das Ereignis ausgelöst wird das Timeout löschen und eine neue erstellen.

z.

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, obwohl Sie die Bedenken trennen und die Funktion als Dienstprogramm herausziehen sollten. – gradbot

+0

sehr raffinierter Trick (mit den dreifach verschachtelten Funktionen), aber schwer zu lesen und folgen der Absicht des Codes und dadurch ist es schwieriger, langfristig zu halten. – gMale

+0

Richtig, wenn es mehr als einmal verwendet würde, würde ich wahrscheinlich die 2 äußeren Ebenen in eine Bibliothek ziehen, wie gradbot es vorschlägt. Dann wäre es eine einfache Funktion, die einen Rückruf nimmt. –

0

Eine schnelle und schmutzige Lösung weniger wäre, den Server zu nennen: Alternativ

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

, ich habe etwas Ähnliches getan, wo ich ein zurückgesetzt haben Timer jedes Mal, wenn ich vom Benutzer "gehört" habe. Sobald der Timer abgelaufen war, rief er meine Aktion an. Daher versucht der Timer ständig zu erlöschen, aber wenn der Benutzer etwas unternimmt, wird der Timer zurückgesetzt. Schließlich stoppt der Benutzer die Bewegung so lange, dass der Timer eine Chance hat, das Ereignis auszulösen.


EDIT:
Nach dem Vorbild von:

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

function userInput() { 
    resetTimer(); 
} 

Wo resetTimer() löscht/startet den Timer. Das würde ungefähr so ​​aussehen:

Ich habe nicht getestet, dass dies kompiliert, aber es sollte Ihnen die Grundidee geben. Dieser Code hat den Vorteil, dass er modular genug ist, um in vielen anderen Sprachen mit nur geringen Änderungen zu funktionieren. Ich folge einer ähnlichen Logik in ActionScript. Außerdem ist es extrem einfach zu lesen, logisch zu folgen und zu warten (6 Monate später, wenn Sie vergessen haben, wie Ihr Code funktioniert).

Ich hoffe, dass in irgendeiner Weise hilft,

--gMale

+0

Javascript kompiliert nicht ^^ – Marko

+0

@Marko sicher, es tut, V8 in Chrom JITs den Code. '^. ^' – gradbot

2

Dieser Code wird dafür sorgen, es war eine halbe Sekunde, da die Veranstaltung im letzten, bevor Sie seine Sache gefeuert wurde (die kommentierte TODO). Ich denke, das ist was du willst.

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

funktioniert, aber verwendet eine globale – gradbot

+1

, die nur von Bedeutung ist, wenn die Chance besteht, dass ein anderes Skript eine globale mit dem gleichen Namen erstellt hat. Wenn es ein Problem ist, könnte die ganze Sache in eine Schließung eingeschlossen werden, aber wenn es nur einmaliges Scripting für eine einzelne Webseite ist, wird es überhaupt keine Rolle spielen. –

4

Es gibt einen wirklich guten Ansatz auf unscriptable.com verfügbar:

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

Dies würde Sie tun:

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

Wenn Sie es vorziehen, keine eigenständige function debounce(func, threshold, execAsap) die Function.prototype gibt es zu vergrößern verfügbar auf der blog post.

+0

+1, ziemlich cool, dass es die Objektreferenz hält und Argumente erlaubt. – gradbot

2

Dies ist Brenton Alker Code, aber in eine Dienstprogrammfunktion verschoben.

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

Lebensretter. Vielen Dank. – mapr

3

Google schlägt eine anderen Zuhörer mit ...

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

Zitat „Beachten Sie, dass Sie auf das bounds_changed Ereignis hören könnten, aber es feuert kontinuierlich, wie die Benutzer Pfannen, sondern der Leerlauf wird ausgelöst, sobald Der Benutzer hat das Schwenken/Zoomen beendet. " /quote

siehe

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

+0

wirkt wie ein Zauber ... das gleiche Gefühl wie mit Ihrem .5 Sekunden-Timer – camel

Verwandte Themen