2009-07-10 4 views
14

Client-Anfrage-Webseite vom Server. Clent fordert dann zusätzliche Berechnungen an; Der Server führt eine Reihe von Berechnungen durch und sendet Teilergebnisse, sobald diese verfügbar sind (Textformat, jede Zeile enthält einen separaten vollständigen Eintrag). Client aktualisiert die Webseite (mit JavaScript und DOM) unter Verwendung der vom Server bereitgestellten Informationen.Cross-Browser-Implementierung von "HTTP-Streaming" (Push) AJAX-Muster

Dies scheint zu passen HTTP Streaming (current Version) Muster von Ajaxpatterns Website.

Die Frage ist, wie man es browser-übergreifend (Browser-agnostisch) macht, vorzugsweise ohne JavaScript-Frameworks zu verwenden, oder ein leichtgewichtiges Framework wie jQuery zu verwenden.

Das Problem beginnt mit der Erstellung von XMLHttpRequest in Browser-übergreifender Weise, aber ich denke, das wichtigste Element ist, dass nicht alle Browser korrekt implementieren onreadystatechange von XMLHttpRequest; nicht alle Browser rufen onreadystatechange Ereignis auf jedem Server Flush (BTW. Wie erzwingen Server Flush aus dem CGI-Skript (in Perl)?). Beispielcode auf Ajaxpatterns behandelt dies mithilfe von Timer; sollte ich die Timer-Lösung abbrechen, wenn ich eine Teilantwort von onreadystatechange feststelle?


Added 11-08-2009

Aktuelle Lösung:
ich die folgende Funktion verwenden XMLHttpRequest-Objekt zu erstellen:

function createRequestObject() { 
     var ro; 
     if (window.XMLHttpRequest) { 
       ro = new XMLHttpRequest(); 
     } else { 
       ro = new ActiveXObject("Microsoft.XMLHTTP"); 
     } 
     if (!ro) 
       debug("Couldn't start XMLHttpRequest object"); 
     return ro; 
} 

Wenn ich verwenden waren einige (vorzugsweise leichte) JavaScript-Framework wie jQuery, würde ich gerne Fallback Benutzer haben wählt die Installation von jQuery aus.

Ich benutze den folgenden Code, um AJAX zu starten; setInterval wird verwendet, weil einige Browsernur aufrufen, nachdem der Server die Verbindung beendet hat (was einige zehn Sekunden dauern kann) und nicht sobald der Server Daten löscht (etwa jede Sekunde oder öfter).

function startProcess(dataUrl) { 
     http = createRequestObject(); 
     http.open('get', dataUrl); 
     http.onreadystatechange = handleResponse; 
     http.send(null); 

     pollTimer = setInterval(handleResponse, 1000); 
} 

Die handleResponse Funktion ist sehr kompliziert, aber die Skizze es sieht wie folgt aus. Kann es besser gemacht werden? Wie würde es mit einem leichten JavaScript-Framework (wie jQuery) gemacht werden?

function handleResponse() { 
    if (http.readyState != 4 && http.readyState != 3) 
     return; 
    if (http.readyState == 3 && http.status != 200) 
     return; 
    if (http.readyState == 4 && http.status != 200) { 
     clearInterval(pollTimer); 
     inProgress = false; 
    } 
    // In konqueror http.responseText is sometimes null here... 
    if (http.responseText === null) 
     return; 

    while (prevDataLength != http.responseText.length) { 
     if (http.readyState == 4 && prevDataLength == http.responseText.length) 
      break; 
     prevDataLength = http.responseText.length; 
     var response = http.responseText.substring(nextLine); 
     var lines = response.split('\n'); 
     nextLine = nextLine + response.lastIndexOf('\n') + 1; 
     if (response[response.length-1] != '\n') 
      lines.pop(); 

     for (var i = 0; i < lines.length; i++) { 
      // ... 
     } 
    } 

    if (http.readyState == 4 && prevDataLength == http.responseText.length) 
     clearInterval(pollTimer); 

    inProgress = false; 
} 
+0

Sie sollten dieses Codebeispiel unbedingt als Antwort hinzufügen und als richtig markieren! –

+4

"wenn der Benutzer jQuery nicht installieren möchte"? – Basic

+0

Hallo, ich bin gerade auf Ihre Lösung gestoßen, aber ich befürchte, dass es immer noch nicht mit dem IE funktioniert, denn wenn Sie versuchen, den responseText zu erhalten, während die Anfragen noch nicht beendet wurden, erhalten Sie Folgendes Meldung: "Die zur Durchführung dieses Vorgangs erforderlichen Daten sind noch nicht verfügbar". –

Antwort

2

Die Lösung, mit der Sie verbunden sind, ist überhaupt nicht AJAX. Sie nennen es HTTP-Streaming, aber es ist im Wesentlichen nur lange Polling.

In dem Beispiel, zu dem sie verlinken, können Sie sich ziemlich leicht mit Firebug sehen. Schalten Sie das Net-Panel ein - es gibt keine XHR-Einträge, aber es dauert nur ein Haar mehr als 10 Sekunden, um die Originalseite zu laden. Das liegt daran, dass sie PHP im Hintergrund verwenden, um die Ausgabe von HTML zu verzögern. Dies ist die Essenz des langen Pollings - die HTTP-Verbindung bleibt offen und das periodisch gesendete HTML ist Javascript-Befehle.

Sie entscheiden können die Abfrage vollständig auf der Client-Seite zu tun, aber mit setTimeout() oder setInterval()

einem jQuery-Beispiel

<script type="text/javascript"> 
    $(document).ready(function() 
    { 
    var ajaxInterval = setInterval(function() 
    { 
     $.getJSON(
     'some/servie/url.ext' 
     , { sample: "data" } 
     , function(response) 
      { 
      $('#output').append(response.whatever);   
      } 
    ); 
    }, 10000); 
    }); 
</script> 
+0

Nicht exaxtly was ich will. Die Berechnung auf dem Server erzeugt die Ausgabe im Klartextformat. Mit XHR kann ich diese Antwort direkt im Client bekommen (onreadystatechange on flush/timer) und die Webseite entsprechend der Daten bearbeiten, die ich bekomme. –

+0

Was ist nicht was du willst? Die lange Umfrage? Ich empfehle keine der beiden Methoden - ich sage Ihnen nur, was Ihre Möglichkeiten sind. –

+0

Wenn Sie Long Pooling (Comet) verwenden möchten, sollten Sie die Meteor Server-Software in Betracht ziehen, da Apache für solche Dinge nicht ausgelegt ist. Und es gibt auch Javascript-Bibliothek, die fast alles für Sie behandelt, ich kann nur nicht daran erinnern, es ist der Name, wird es später veröffentlichen. – usoban

0

Ich würde umkreiste

einen Blick

Sie verwenden mehrere Comet-Transport-Implementierungen, die sie basierend auf Konfiguration und Browser-Sniffing auswählen.

Siehe http://orbited.org/svn/orbited/trunk/daemon/orbited/static/Orbited.js

und suchen Sie nach „Orbited.CometTransports“

Einige der verschiedenen Transporte durch die Back-End-Implementierung angepasst werden müssen, um einen Blick auf die Serverseite auch für umkreiste.