11 Stimmen

Wie reagiert man auf ein Javascript-Ereignis nur, wenn es einmal ausgelöst wurde und dann innerhalb eines bestimmten Zeitraums nicht erneut ausgelöst wird?

In meiner Anwendung höre ich auf das Google Maps API 'bounds_changed' Ereignis, um einen Ajax-Aufruf zu senden und einige div auf der Webseite basierend auf den neuen Grenzen der Karte zu aktualisieren:

google.maps.event.addListener(map, 'bounds_changed', function() {
  // hier erfolgt ein Ajax-Aufruf
}

Das Ereignis 'bounds_changed' wird mit hoher Frequenz ausgelöst, wenn der Benutzer die Karte herumschiebt. So sehr, dass zu viele Ajax-Anfragen an den Server gesendet werden.

Grundsätzlich möchte ich den Ajax-Aufruf nur durchführen, nachdem der Benutzer aufgehört hat, die Karte für einen bestimmten Zeitraum zu verschieben (zum Beispiel 500 ms). Ich bin nicht sehr erfahren mit Javascript und habe versucht, dies mit setTimeout und clearTimeout zu erreichen, aber ohne Erfolg.

Jeder Vorschlag wäre willkommen :)

12voto

Brenton Alker Punkte 8747

Fügen Sie ein Timeout hinzu, das Ihren Code 500 ms nach dem Auslösen des Ereignisses ausführt. Jedes Mal, wenn das Ereignis ausgelöst wird, löschen Sie das Timeout und erstellen Sie ein neues.

zB.

google.maps.event.addListener(map, 'bounds_changed', (function () {
    var timer;
    return function() {
        clearTimeout(timer);
        timer = setTimeout(function() {
            // hier erfolgt ein Ajax-Aufruf
        }, 500);
    }
}()));

4voto

gnarf Punkte 103284

Es gibt einen wirklich guten Ansatz auf unscriptable.com:

Function.prototype.debounce = function (threshold, execAsap) {
    var func = this, // Verweis auf die originale Funktion
        timeout; // Handle zum setTimeout-Async-Task (Detektionszeitraum)
    // Gib die neue gedeublockte Funktion zurück, die die originale Funktion nur einmal ausführt, bis der Detektionszeitraum abgelaufen ist
    return function debounced () {
        var obj = this, // Verweis auf das originale Kontextobjekt
            args = arguments; // Argumente zur Ausführungszeit
        // Dies ist die Detektionsfunktion. Sie wird ausgeführt, wenn der Zeitraum abläuft
        function delayed () {
            // Wenn wir am Ende des Detektionszeitraums sind
            if (!execAsap)
                func.apply(obj, args); // jetzt ausführen
            // Timeout-Handle löschen
            timeout = null;
        };
        // Aktuellen Detektionszeitraum stoppen
        if (timeout)
            clearTimeout(timeout);
        // Andernfalls, wenn wir nicht bereits warten und am Anfang des Wartezeitraums ausführen
        else if (execAsap)
            func.apply(obj, args); // jetzt ausführen
        // Wartezeitraum zurücksetzen
        timeout = setTimeout(delayed, threshold || 100);
    };
}

Dies würde es Ihnen ermöglichen:

// Funktion 200ms nach dem letzten Auslösen des bounds_changed-Ereignisses aufrufen:
google.maps.event.addListener(map, 'bounds_changed', (function() {
  // hier kommt ein Ajax-Aufruf
}).debounce(200));

// Funktion nur einmal alle 200ms aufrufen:
google.maps.event.addListener(map, 'bounds_changed', (function() {
  // hier kommt ein Ajax-Aufruf
}).debounce(200,true));

Wenn Sie es bevorzugen, das Function.prototype nicht zu erweitern, gibt es eine eigenständige function debounce(func, threshold, execAsap) auf dem Blog-Beitrag verfügbar.

4voto

camel Punkte 91

Google schlägt vor, einen anderen Listener zu verwenden ...

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

Zitat "Beachten Sie, dass Sie das bounds_changed-Ereignis abhören könnten, aber es wird kontinuierlich ausgelöst, während der Benutzer im Schwenkmodus ist. Der idle wird stattdessen ausgelöst, sobald der Benutzer mit dem Schwenken/Zoomen aufgehört hat." /Zitat

siehe

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

2voto

Dagg Nabbit Punkte 72150

Dieser Code stellt sicher, dass eine halbe Sekunde vergangen ist, seit das Ereignis das letzte Mal ausgelöst wurde, bevor es seine Aufgabe erledigt (das kommentierte TODO). Ich denke, das ist das, was du willst.

var mapMoveTimer;
google.maps.event.addListener(map, 'bounds_changed', function(){
  clearTimeout(mapMoveTimer);
  mapMoveTimer = setTimeout(function(){
    // TODO: Hier kommt der Karten-Code
  }, 500); 
});

2voto

gradbot Punkte 13574

Dies ist Brenton Alkers Code, der jedoch in eine Hilfsfunktion verschoben wurde.

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(){
    // Hier erfolgt ein Ajax-Aufruf
}));

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X