Wie Inhalte die nur langsam geliefert werden sofort anzeigen?



  • Hallo,

    ich hab hier eine kleine Embedded-Schachtel auf der ein simpler HTTP-Server (in C geschrieben) läuft welcher HTML-Seiten anbietet die den aktuellen Systemzustand u.ä. widerspiegeln. Diese Seiten werden natürlich dynamisch zum Zeitpunkt der Anfrage erzeugt. Leider dauern mache der Vorgänge zum ermitteln bestimmter Zustände u.ä. etwas länger (einige Sekunden bis wenige Minuten sind möglich) so das die entsprechende HTML-Seite erst nach einiger Zeit vollständig im Firefox ankommt. Der HTTP-Server weiß natürlich wann er einen längeren Vorgang benötigt und macht auf die TCP-Verbindung vorher einen flush() so das alle bisherigen Daten komplett gesendet werden und im vorerst letzten TCP-Paket auch das Push-Flag gesetzt ist (ich hab das mit Wireshark nachgeprüft, das funktioniert ordentlich) so das ich davon ausgehe das Firefox zumindest bis zum aktuellen Punkt alle HTML-Daten hat und diese eigentlich auch anzeigen sollte aber das Fenster bleibt leer. Firefox baut die HTML-Seite erst dann auf wenn das HTML-Dokument vollständig übertragen wurde (also das abschließende </html>-Tag kam) und bis da hin passiert aus Sicht des Users gar nichts.

    Kann man dieses Problem irgendwie lösen?
    Gibt es eine Möglichkeit Firefox anzutriggern das er die bereits empfangenen HTML-Daten schon mal darstellt? Zumindest der HTML-Header und das Seiten-Menü und ähnliches sind auf jeden Fall schon gesendet bevor die erste Pause kommt und das würde ich schon gerne sehen damit die Seite als ganzes permanent bedienbar bleibt.

    Ich kann mich erinnern das Firefox früher sowas konnte aber das war wimre eine recht große Seite (der HTML-Code war über 1 MByte) und meine HTML-Seiten von der Embdedded-Schachtel sind kaum 20 kBytes.
    Könnte es damit zusammenhängen das einfach bestimmte Datenmengen nicht erreicht werden damit Firefox schon mal anfängt auch unvollständigen HTML-Code zu rendern und darzustellen?

    Grüße
    Erik



  • Du könntest die Daten statisch ablegen bzw. per Cron-Job regelmäßig aktualisieren lassen. Dann muss der Web-Server nur noch die statische Seite ausliefern.



  • Hallo,

    oenone schrieb:

    Du könntest die Daten statisch ablegen bzw. per Cron-Job regelmäßig aktualisieren lassen.

    Nein das geht nicht. Es handelt sich meistens um dynamische Daten die erst in dem Moment des HTTP-Zugriffs ermittelt werden können (um wirklich den aktuellen Zustand des Systems darzustellen) oder um Jobs die erst durch den HTTP-Zugriff gestartet werden (und meistens Parameter per URI-Query bekommen) und deren Ergebnis oft etwas Zeit braucht bzw. in mehreren Häppchen mit etwas zeitlichen Abstand kommen.

    Ich hab mir heute mal angeschaut welche Möglichkeiten es per JavaScript gibt aber das XMLHttpRequest-Objekt ist auch blockierend in dem Sinne das der Response für das JavaScript erst zur Verfügung steht wenn er komplett empfangen wurde. Auch da scheint es im Browser keine Möglichkeit zu geben schon mal die Bytes zu verarbeiten die bereits empfangen wurden obwohl noch welche fehlen.

    Achja, mein HTTP-Server schickt bei keinem Response einen Content-Length-Header mit so das es wohl wirklich darauf ankommt das die TCP-Verbindung geschlossen sein muss bevor man die Daten im Browser verarbeiten/darstellen kann.

    Grüße
    Erik



  • Du könntest per HTML ein statisches Grundgerüst anbieten und die individuellen Datenfelder mit einzelnen AJAX-Requests laden und bis dahin Platzhalter anzeigen.

    Wobei ich mich frage, wie aktuell Daten sein können, deren Ermittlung "bis zu mehrere Minuten" dauern kann...



  • Hallo,

    Dasd schrieb:

    Du könntest per HTML ein statisches Grundgerüst anbieten und die individuellen Datenfelder mit einzelnen AJAX-Requests laden und bis dahin Platzhalter anzeigen.

    Ja, aber auch dort werden alle Ergebnisse erst dann angezeigt wenn sie vollständig vorliegen (auch XMLHttpRequest gibt die Daten erst dann raus wenn die TCP-Verbindung geschlossen wurde, also der Browser sicher ist das nichts mehr kommt) oder ich müsste versuchen das über mehrere (potentiell recht viele) Zugriffe (und entsprechend viele TCP-Verbindungen mit entsprechendem Ressourcenverbrauch) aufzuteilen und das würde doch eine ziemlich hohe Komplexität im HTTP-Server verursachen (persistente Jobverwaltung usw., über mehrere eventuell sogar überlappende/zeitgleiche Requests) und das möchte ich bei einer kleinen Embedded-Schachtel sehr gerne vermeiden. Weder CPU-Leistung noch RAM sind dort großzügig bemessen, es gilt also größtmögliche Sparsamkeit.

    Dasd schrieb:

    Wobei ich mich frage, wie aktuell Daten sein können, deren Ermittlung "bis zu mehrere Minuten" dauern kann...

    Okay, das mit den Minuten kommt nur zustande wenn alle möglichen TimeOuts erst abgewartet werden müssen, die meisten Jobs dauern im Regelfall höchstens ein paar Sekunden aber auch im Fehlerfall muss die Anlage bedienbar sein.

    Mir wäre es am liebsten es gäbe eine Möglichkeit den Browser dazu zu bringen den bereits empfangenen HTML-Code immer so schnell wie möglich darzustellen, selbst dann wenn noch Teile fehlen und der Rest nur häppchenweise kommt.
    Gibt es denn in dieser Richtung keinen Trick o.ä.?

    Grüße
    Erik



  • Das scheint mir ziemlich browserspezifisch zu sein. Du könntest ja mal http://stackoverflow.com/questions/6089921/firefox-4-doesnt-render-partial-pages ausprobieren. Die zweite Antwort wirkt recht vielversprechend.



  • Hallo,

    Dasd schrieb:

    Das scheint mir ziemlich browserspezifisch zu sein.

    Weiß ich nicht, aber ich werde mal versuchen verschiedene Browser zu probieren. Viele werden das aber nicht da in der Maschine nur Linux-Rechner verfügbar sind.

    Dasd schrieb:

    Du könntest ja mal http://stackoverflow.com/questions/6089921/firefox-4-doesnt-render-partial-pages ausprobieren. Die zweite Antwort wirkt recht vielversprechend.

    Gerade diese Antwort sagt mir gar nichts. Was soll den Bitte in das <script>-Tag rein das hinter dem </html> kommt? Etwa ein JavaScript das per XMLHttpRequest die eigentlichen Ergebnisdaten holt und ins HTML-Gerüst einbaut? Dieses Script kann auch gleich am Anfang ins HTML eingebaut werden (da wo es korrekt hingehört). Die eigentlichen Ergebnisdaten kommen wohl bestimmt nicht pur hinter das abschließende </html>. Mal ganz davon abgesehen das ich alle ausgelieferten HTML-Seiten als valides XHTML 1.1 markiere und mir auch Mühe gebe das dem wirklich so ist.

    Die Antwort vom svick am May 23 '11 at 17:53 entspricht zumindest eher meiner persönlichen subjektiven Einschätzung. Ich schätze ich werd noch mal Google benutzen und wenn das zu keinem Ergebnis führt mal versuchen bei den Programmierern nachzufragen.

    Zumindest ist das Problem des Fragestellers mit meinem ziemlich identisch, Danke für diesen Hinweis.

    Grüße
    Erik


  • Mod

    Die korrekte Loesung ist cronjob und die Daten cachen. Kann ja durchaus jede Minute 1 mal passieren.

    Wenn das nicht geht, dann eben per ajax nachladen.



  • Hallo,

    Shade Of Mine schrieb:

    Die korrekte Loesung ist cronjob

    Nein, die korrekte Lösung ist das Redering-Mantra von 1994 "show as much as you can as soon as you can", siehe http://blog.codinghorror.com/the-lost-art-of-progressive-html-rendering/.

    Shade Of Mine schrieb:

    und die Daten cachen. Kann ja durchaus jede Minute 1 mal passieren.

    Viele der Jobs benötigen Parameter die absolut nicht vorhersagbar sind und deren theoretische Anzahl an Kombinationsmöglichkeiten die Größe von RAM auf diesem Planeten deutlich übersteigen dürfte.
    Nebst dessen das ich noch einmal drauf hinweisen möchte das es sich um eine kleine Embedded-Schachtel mit wenig RAM und auch nur wenig CPU-Leistung handelt, spekulative Jobausführung ist da absolut nicht möglich.

    Shade Of Mine schrieb:

    Wenn das nicht geht, dann eben per ajax nachladen.

    Aber auch AJAX hilft über dieses Problem nur bedingt hinweg oder erfordert eine hohe Komplexität und Arbeitslast (sowohl im Browser als auch im HTTP-Server), siehe mein Posting vom 16.07.

    Ich hab heute ein paar Dinge bezüglich Firefox herausgefunden die ich morgen mal testen will, vielleicht komme ich ja so doch zu einer Lösung.

    Grüße
    Erik


  • Mod

    erik.vikinger schrieb:

    Hallo,

    Shade Of Mine schrieb:

    Die korrekte Loesung ist cronjob

    Nein, die korrekte Lösung ist das Redering-Mantra von 1994 "show as much as you can as soon as you can", siehe http://blog.codinghorror.com/the-lost-art-of-progressive-html-rendering/.

    Nein. Das ist etwas ganz anderes.

    Shade Of Mine schrieb:

    Wenn das nicht geht, dann eben per ajax nachladen.

    Aber auch AJAX hilft über dieses Problem nur bedingt hinweg oder erfordert eine hohe Komplexität und Arbeitslast (sowohl im Browser als auch im HTTP-Server), siehe mein Posting vom 16.07.

    Nein, ist trivial.
    Welche Probleme hast du denn damit?

    Es darf ja ruhig laenger dauern, das tut doch nicht weh - du zeigst solange einen Ladebalken an. Du kannst ueber mehrere Requests so granular wie du willst laden.

    Du machst dir das alles viel komplexer als es ist.



  • Hallo,

    Shade Of Mine schrieb:

    erik.vikinger schrieb:

    "show as much as you can as soon as you can"

    Nein. Das ist etwas ganz anderes.

    Natürlich sind die Art der Informationsgewinnung und die Art der Informationsdarstellung zwei verschiedene Dinge aber mein Problem liegt an der Darstellung der Informationen durch den Browser und nicht an der Art der Informationsgewinnung in meiner Embedded-Schachtel.

    Shade Of Mine schrieb:

    Nein, ist trivial.
    Welche Probleme hast du denn damit?

    Schon allein das überhaupt mehrere TCP-Verbingungen benötigt werden um alle Ergebnisse eines zusammenhängenden Jobs zum Browser zu transportieren macht AJAX sicher nicht mehr trivial. Und das nicht nur weil dann mein HTTP-Server die Fähigkeit benötigt mehrere TCP-Verbindungen also HTTP-Requests einem einzelnen/spezifischen Job zuzuordnen sondern weil dann die Ergebnis-Daten auch mal in der Embedded-Schachtel gepuffert werden müssen weil z.B. zwischen zwei Teilergebnissen der Browser noch nicht den nächsten XMLHttpRequest abgesetzt hat. Oder was ist wenn sich mal zwei XMLHttpRequest-Zugriffe auf den selben Job überlappen? Mag sein das sowas unter normalen Umständen nicht passiert aber mein HTTP-Server wird auf jeden Fall auch mit so einer Situation anständig fertig werden müssen.

    Shade Of Mine schrieb:

    Du machst dir das alles viel komplexer als es ist.

    Ich bin der Meinung das meine derzeitige Lösung die einfachst mögliche ist. Der Browser baut eine einzelne TCP-Verbindung mit einem einzelnen HTTP-Request auf und meine Embedded-Schachtel sendet über diese eine TCP-Verbindung die Daten so schnell wie sie eben entstehen. Das einzigste was an diesem Szenario ein Problem darstellt ist das der Browser diese Daten nicht sofort darstellt sondern wartet bis alles da ist, entgegen dem nun 20 Jahre alten HTML-Redering-Mantra.

    Mein HTTP-Server besteht momentan aus gut 15kBytes C-Code, das umfasst sämtliches HTTP-Parsing und auch das Zerlegen von URI-Queries in fertige Häppchen so das die eigentlichen Handler (die für die einzelnen URLs zuständig sind) alles mundgerecht serviert bekommen und dort höchstens noch die Job-Spezifischen Auswertungen drin sind. Dazu kommen noch knapp 10kBytes C-Code für die Generierung des HTML-Basisgerüsts inklusive des Menüs das in jede HTML-Seite eingebunden wird. Die eigentlichen Handler liefern nur noch den eigentlichen Content und manche davon sind weniger als 3kBytes C-Code und das trotz dessen das dort z.B. eine HTML-Tabelle mit einer variablen Anzahl an Zeilen für die dynamisch ermittelten Daten generiert wird. Wenn ein Job mal länger braucht wird das alles per Call-Backs realisiert und diese Call-Back-Funktionen bekommen immer den TCP-Socket-Descriptor als Parameter und reichen diesen Descriptor entweder zum nächsten Teil-Job weiter oder beenden die TCP-Verbindung falls der Job als ganzes beendet ist. Die überwiegend meisten dieser Call-Back-Funktionen sind kaum 50 Zeilen.

    Ich bin wirklich der Meinung das es kaum noch einfacher geht aber wenn jemand eine Lösung mit AJAX kennt die ebenso simpel in meiner Embedded-Schachtel umgesetzt werden kann und möglichst auch keinen größeren Speicherbedarf (z.B. wegen zusätzlicher TCP-Sockets (die ja auch nach dem Ende einer TCP-Verbindung immer noch eine Weile am Leben sind) oder Pufferplatz für die Ergebnis-Daten) verursacht dann würde ich das gerne hier lesen. Ich stehe alternativen Ideen durchaus aufgeschlossen gegenüber, mein Problem sind die arg begrenzten Ressourcen auf der Embedded-Schachtel.

    Ich hab hier keinen fetten Apache mit PHP und MySQL Backends auf X GHz-Multicore mit X GBytes RAM, sondern ich hab 50 MHz-Singelcore mit 4 MByte RAM und dieses System soll hauptberuflich eine Maschine in Echtzeit steuern, der HTTP-Server ist da nur ein Nebenbei-Hobby.

    Grüße
    Erik



  • Versuch doch mal die zu übertragende Datenmenge zu reduzieren. Also z.B: eine Komrpimierung mit gzip, deflate zu implementieren. Gerade Text lässt sich doch wahnsinnig gut komprimieren. Je nach Netzwergeschwindigkeit und Datenmenge kann sich das richtig lohnen.



  • Ansonsten könntest du noch versuchen Chunked-Encoding zu implementieren.



  • erik.vikinger schrieb:

    Shade Of Mine schrieb:

    Nein, ist trivial.
    Welche Probleme hast du denn damit?

    Schon allein das überhaupt mehrere TCP-Verbingungen benötigt werden um alle Ergebnisse eines zusammenhängenden Jobs zum Browser zu transportieren macht AJAX sicher nicht mehr trivial. Und das nicht nur weil dann mein HTTP-Server die Fähigkeit benötigt mehrere TCP-Verbindungen also HTTP-Requests einem einzelnen/spezifischen Job zuzuordnen sondern weil dann die Ergebnis-Daten auch mal in der Embedded-Schachtel gepuffert werden müssen weil z.B. zwischen zwei Teilergebnissen der Browser noch nicht den nächsten XMLHttpRequest abgesetzt hat. Oder was ist wenn sich mal zwei XMLHttpRequest-Zugriffe auf den selben Job überlappen? Mag sein das sowas unter normalen Umständen nicht passiert aber mein HTTP-Server wird auf jeden Fall auch mit so einer Situation anständig fertig werden müssen.

    Ich verstehe das Problem auch nicht.
    Erster Request an den Server liefert eine vollständiges, statisches HTML, was sich überhaupt nicht für die Daten interessiert.
    Ist die Seite geladen, wird der zweite (Ajax-)Request abgesetzt, der reine Daten anfordert.


  • Mod

    Jockelx schrieb:

    Ich verstehe das Problem auch nicht.
    Erster Request an den Server liefert eine vollständiges, statisches HTML, was sich überhaupt nicht für die Daten interessiert.
    Ist die Seite geladen, wird der zweite (Ajax-)Request abgesetzt, der reine Daten anfordert.

    Exakt.
    Das HTML dass auf den ersten Request gesendet wird kann dann schöne Ladeanimationen enthalten und je nachdem wie granular man es machen will lädt man jede Information die man Anzeigen will per eigenen ajax request oder alle zusammen in einem.

    Das ist trivial und das ist der Standardweg. Der wird auf Millionen von Webseiten eingesetzt. Es gibt ganze JavaScript Libraries die dieses Verhalten umsetzen.

    Wie gesagt: hier wird viel zu kompliziert gedacht. Die Aufgabenstellung ist trivial. Die Lösung ist noch viel simpler. Man kann nämlich in dem ajax request sogar ein HTML fragment returnen und muss nicht mal irgendwas in JS postprozessen.


Anmelden zum Antworten