2017-06-15 4 views
2

Ich habe eine Javascript-Anwendung erstellt, die ein Diagramm mit einigen Dropdown-Filter, die Benutzer ändern können, hat. Die Dropdownlisten verfügen alle über Ereignis-Listener, die eine Serveranforderung senden, um die Daten zu erhalten (über einen JQuery-Ajax-Aufruf) und anschließend die Daten grafisch darstellen. Das Problem ist, wenn der Benutzer die Tastatur verwendet, um schnell durch viele verschiedene Elemente des Dropdown-Menüs zu gehen.Töte Ajax-Anrufe, wenn eine neue ausgelöst wird

Der Serveraufruf dauert ungefähr eine Sekunde, wenn sie also schnell durch 20 scrollen, kann dies zu einer Anhäufung führen. Es werden 20 verschiedene Anforderungen an den Server erstellt, und dann gibt es nicht einmal eine Garantie, dass der letzte Code, der bei Serveranforderung ausgeführt wird, der aktuellste Filter ist.

Also meine Frage ist, was ist der beste Weg, wenn ein Filter geändert wird, um alle anderen asynchronen Prozesse zu beenden? Hier ist der relevante Code:

$("#filter").change(function(d) { 
    getData(); 
} //end of if 
}); 

function getData() { 
    ... 
    $.ajax({ 
    url: myUrl 
    type: "GET", 
    dataType: "json", 
    success: function(d) { 
     [do some stuff] 
     } //end of success function 
    }); //end of ajax 
} //end of getData 
+0

Sie haben eine zusätzliche geschweifte Klammer in dieser ersten Funktion sagt es schließt ein 'if'. – AtheistP3ace

+0

Sie sollten warten, bis die aktuell ausgeführte Anfrage beendet ist, bevor Sie eine neue Anfrage senden (und einige Anfragen auslassen, die während der Ausführung der aktuellen Anfrage auftreten könnten). Selbst wenn Sie die 'Abbruch'-Funktionalität von' XMLHttpRequest2' verwenden würden, könnte dies immer noch zu einer unnötig hohen Serverlast führen. –

+0

Mögliches Duplikat von [Früheren AJAX-Aufruf abbrechen, wenn ein neuer erstellt wird?] (Https://stackoverflow.com/questions/9285271/abort-previous-ajax-call-when-a-new-one-made) –

Antwort

1

speichern alle Ajax-Aufrufe Sie in eine Variable abbrechen möchten, dann können Sie den letzten Anruf abbrechen.

Dies ist eine sehr häufig Praxis, wenn einiger Ajax-Aufruf viele Male, bevor die, die passieren könnte, bevor es eine Chance beenden mußte.

function getData(){ 
    $filter.data('REQ') && $filter.data('REQ').abort(); // abort the last request before creating a new one 

    return $.ajax({ 
     url:myUrl 
     type:"GET", 
     dataType:"json", 
     success:function(d){ 
      [do some stuff] 
     } 
    }) 
} 

var $filter = $("#filter"); 

$filter.on('change', function(d) { 
    $filter.data('REQ', getData()) 
}); 

Of-Kurs ist dies eine sehr vereinfachte Art Code, und Sie sollten diese in einer strukturierten Art und Weise neu schreiben, aber es gibt Ihnen eine Vorstellung davon, wie die letzte Ajax-Request zwischenzuspeichern und dann haben Sie die Möglichkeit, diese vor dem Senden eines neuen Anrufs abzubrechen.


Übrigens hat Ihr Titel nichts mit der Frage zu tun. Sie fragen, wie Sie eine Abfolge von Ajax-Anrufen handhaben, aber nach Ereignissen fragen. Diese Frage hat nichts mit Ereignissen zu tun, daher sollten Sie den Titel so ändern, dass er zu dem Problem passt.


aktualisieren in Bezug auf was @ t.niese in den Kommentaren gesagt hatte:

Drosselung der Anforderungen auf der Client-Seite ist auch ein gutes Spiel zu tun, da der Server nicht wirklich, wenn der Kunde wissen können hat die Anfrage abgebrochen oder nicht, und wenn es eine ressourcenintensive Anfrage ist, sollte sie gedrosselt werden. ABER, ich würde vorschlagen, die Anfragen auf der Serverseite und nicht auf der Client-Seite, wenn möglich, Drosseln, weil clientseitige Drosselung könnte umgangen werden und ist nicht 100% zuverlässig, und es "kostet" die gleiche Menge Zeit, dies auf der Serverseite zu tun.

Can a http server detect that a client has cancelled their request?

+1

Ich habe geändert der Code ein bisschen, nur die Ajax-Anfrage an eine Variable mit globalem Gültigkeitsbereich gespeichert und abort für diese Variable am Anfang von getData aufgerufen, aber der Ansatz funktioniert perfekt dank. – zachvac

+0

froh, dass es funktioniert und ich bin froh, dass Sie etwas Neues gelernt haben. – vsync

+0

Es sollte erwähnt werden, dass "abort" nur die Anfrage auf der Client-Seite stoppt, aber sobald es den Server trifft, muss der Server möglicherweise noch die gesamte Verarbeitung für die Anfrage durchführen, selbst wenn es abgebrochen wurde. Es hat also keine Auswirkungen auf die Serverlast, und wenn dies zu einem Flaschenhals führt, wird 'abbrechen' nicht helfen und die Anzahl der ausgegebenen Anfragen sollte gedrosselt werden. @zachvac –

-1

Ich würde fallen alle Versuche, eine neue Anforderung initiieren getData aufrufen, während eine aktuelle Anforderung ausgeführt wird, und nur so schnell die letzte getData Versuch senden, wie die aktuelle Anforderung abgeschlossen ist. Dadurch wird sichergestellt, dass die Serverlast nicht unnötig hoch wird, da nur eine Anfrage ausgeführt wird.

var currentRequest; 
var resubmitRequest; 

function getData() { 

    // only start a new request id no current request is running 
    if (!currentRequest) { 
    resubmitRequest = false; 
    currentRequest = Promise.resolve($.ajax({ 
     url: myUrl 
     type: "GET", 
     dataType: "json" 
    })); //end of ajax 

    currentRequest 
     .then((d) => { 
     [do some stuff] 
     }) 
     .finally(() => { 
     // if the current request finished and another attempt to request data 
     // happened while this request was running then call getData again 
     if (resubmitRequest) { 
      getData() 
     } 
     }) 

    } else { 
    // store the information that the data has to be requested 
    // another time after the currently running request finished 
    resubmitRequest = true; 
    } 

    return currentRequest; 
} //end of getData 
-1

Sie können es einfach zum Beispiel auf 500mil Sekunden pausieren und dann 'letzte' Änderung ausführen und diesen Ajax-Aufruf ausführen ..

$("#filter").change(function(d) { 
    if($.active > 0) return false; 
    // do not run new ajax if last one is not finished 
    clearTimeout(window.timer); 
    // if new 'change' evt is raised in less then 500 mils 
    // then clear it and run 'last' one 
    window.timer = setTimeout(function(){ 
    getData(); 
    }, 500); 
}); 

im Fall, wenn der Benutzer es ändert mich während Ajax tun, return false it :)

-1

Mit wenig Aufwand können Sie Ihre eigenen handler für diese Fälle können Code:

function handler(ms, fn) { 
    var eventId; 
    return function() { 
     // if there is an event programmed, kill it 
     clearTimeout(eventId); 
     // and program the new one (replace the event) 
     eventId = setTimeout(fn); 
     // if passed the time no event was programmed, setTimeout is going to execute the function 
    } 
} 

// execute getData if no event is fired in a 1000ms interval (the user stopped typing) 
// getData is the same that you have 
var fn = handler(1000, getData); 

$("#filter").change(fn); 
Verwandte Themen