2010-01-19 14 views
5

Ich schreibe eine Webapp (Firefox-kompatibel nur), die lange Polling (über jQuery Ajax Fähigkeiten) verwendet, um mehr oder weniger konstante Updates vom Server an den Client zu senden. Ich mache mir Sorgen über die Auswirkungen, wenn ich das ganze für lange Zeit laufen lasse, sagen wir den ganzen Tag oder über Nacht. Der Basiscode Skelett ist dies:Verbesserung der Long-Polling Ajax Leistung

function processResults(xml) 
{ 
    // do stuff with the xml from the server 
} 

function fetch() 
{ 
    setTimeout(function() 
    { 
     $.ajax({ 
      type: 'GET', 
      url: 'foo/bar/baz', 
      dataType: 'xml', 
      success: function (xml) 
      { 
       processResults(xml); 
       fetch(); 
      }, 
      error: function (xhr, type, exception) 
      { 
       if (xhr.status === 0) 
       { 
       console.log('XMLHttpRequest cancelled'); 
       } 
       else 
       { 
        console.debug(xhr); 
        fetch(); 
       } 
      } 
     }); 
    }, 500); 
} 

(. Die halbe Sekunde „Schlaf“ ist so, dass der Client den Server nicht hämmern, wenn der Updates an den Client zurückkommen schnell - was sie sind in der Regel)

Nachdem es über Nacht laufen gelassen wurde, neigt es dazu, Firefox zu crawlen. Ich dachte, dass dies teilweise durch eine große Stapeltiefe verursacht werden könnte, da ich im Grunde eine unendlich rekursive Funktion geschrieben habe. Wenn ich jedoch Firebug verwende und einen Breakpoint in fetch werfe, sieht das so aus. Der Stack, den Firebug mir zeigt, ist nur etwa 4 oder 5 Frames tief, selbst nach einer Stunde.

Eine der Lösungen, die ich betrachte, ändert meine rekursive Funktion in eine iterative, aber ich kann nicht herausfinden, wie ich die Verzögerung zwischen Ajax Anfragen ohne Spinning einfügen würde. Ich habe mir die JS 1.7 "yield" keyword angesehen, aber ich kann meinen Kopf nicht ganz umschließen, um herauszufinden, ob es das ist, was ich hier brauche.

Ist die beste Lösung, nur um eine harte Aktualisierung auf der Seite regelmäßig, sagen wir, einmal pro Stunde zu tun? Gibt es ein besseres/schlankeres Designdesign mit langen Pollings, das selbst nach 8 oder 12 Stunden keine Probleme mit dem Browser verursacht? Oder sollte ich das lange Polling einfach überspringen und ein anderes "constant update" -Muster verwenden, da ich normalerweise weiß, wie oft der Server eine Antwort für mich hat?

Antwort

2

Es ist auch möglich, dass es FireBug ist. Sie sind console.logging Sachen, was bedeutet, dass Sie wahrscheinlich eine Netzwerkmonitor Registerkarte geöffnet haben, usw., was bedeutet, dass jede Anfrage im Speicher gespeichert wird.

Versuchen Sie es zu deaktivieren, sehen Sie, ob das hilft.

+0

Das hilft mir !! – JulienFr

2

Ich vermute, dass Speicher aus processResults() leckt.

Ich habe in einer Webanwendung mit langer Abfrage, die wochenlang ununterbrochen ohne Seitenaktualisierung ausgeführt werden kann, einen sehr ähnlichen Code wie Ihren verwendet.

Ihr Stapel sollte nicht tief sein, weil fetch() sofort zurückkehrt. Sie haben keine unendlich rekursive Schleife.

Sie können den Firefox Leak Monitor Add-on verwenden, um Sie bei der Suche nach Speicherlecks zu unterstützen.

+0

Ich dachte das als eine andere Möglichkeit, um die Stack-Tiefe zu "brechen", aber ich sehe nicht, dass es einen anderen Effekt als 'setTimeout' in meinem ursprünglichen Code hat. –

+0

Ja, aber Ihr Stack sollte nicht tief gehen, da fetch() sofort zurückkehrt, so dass die Erfolgs- und Fehlerfunktionen ziemlich schnell aus dem Stack verschwinden. –

+0

Ich vermute, dass Ihr Speicher von 'processResults()' leckt. –

1

Die Stapeltiefe von 4-5 ist korrekt. setTimeout und $.ajax sind asynchrone Aufrufe, die sofort zurückgeben. Der Callback wird später vom Browser mit einem leeren Call-Stack aufgerufen. Da Sie Long Polling nicht synchron implementieren können, müssen Sie diesen rekursiven Ansatz verwenden. Es gibt keine Möglichkeit, es iterativ zu machen.

Ich vermute, der Grund für diese Verlangsamung ist, dass Ihr Code ein Speicherleck hat. Das Leck könnte entweder in $.ajax von jQuery (sehr unwahrscheinlich) oder in Ihrem processResults Anruf sein.

1

Es ist eine schlechte Idee, fetch() von innerhalb der Methode selbst aufzurufen. Rekursivität wird besser verwendet, wenn Sie erwarten, dass die Methode irgendwann endet und die Ergebnisse an den Aufrufer gesendet werden.Die Sache ist, wenn Sie die Methode rekursiv aufrufen, hält sie die Aufrufermethode offen und verwendet Speicher. Wenn Sie nur 3-4 Frames tief sind, liegt es daran, dass jQuery oder der Browser irgendwie "reparieren", was Sie getan haben.

Die letzten Versionen von jquery unterstützen standardmäßig das Long-Polling. Auf diese Weise können Sie sicher sein, dass Sie nicht auf die Intelligenz des Browsers angewiesen sind, um mit Ihrem unendlichen rekursiven Anruf umzugehen. Wenn Sie die $.ajax() Methode aufrufen, können Sie den folgenden Code verwenden, um eine lange Abfrage durchzuführen, kombiniert mit einer sicheren Wartezeit von 500 Millisekunden vor einem neuen Anruf.

function myLongPoll(){ 
    setTimeout(function(){ 
     $.ajax({ 
      type:'POST', 
      dataType: 'JSON', 
      url: 'http://my.domain.com/action', 
      data: {}, 
      cache: false, 
      success:function(data){ 

       //do something with the result 

      }, 
      complete: myLongPoll, 
      async : false, 
      timeout: 5000 
     }); 
    //Doesn't matter how long it took the ajax call, 1 milisec or 
    //5 seconds (timeout), the next call will only happen after 2 seconds 
    }, 2000); 

Auf diese Weise können Sie sicher sein, dass der $.ajax() Aufruf, bevor der nächste beginnt geschlossen ist. Dies kann durch Hinzufügen einer einfachen console.log() beim ersten und anderen nach Ihrem $.ajax() Anruf nachgewiesen werden.

+0

Die Verwendung von jQuery 'Complete' Callback unterscheidet sich nicht signifikant von der Implementierung in meiner Frage. Dies ist kein Java - Anrufer müssen niemals XHRs oder andere Ressourcen explizit schließen. –

Verwandte Themen