Home
Navigation
Impressum
SEO Welten - Webcoding, Editoren, Scripte und Anwendungen
SEO Welten
Buchempfehlungen
 

Ajax: Parallel Requests gleichzeitig ausführen

Ajax-Requests nebeneinander und hintereinander ausführen

Übersicht / Seite:

  1. Content mit Ajax verarbeiten (eine kleine Einführung)

    5.1 Verarbeitung von XML-Dateien (Attribute einlesen und ausgeben)
    5.2 Mehrere Requests ausführen (Requests hintereinander abarbeiten)
    5.3 Parallel Requests ausführen (Anfragen gleichzeitig senden)


Aufgabenstellung und Umsetzung

Auf der vorausgehenden Seite wurde in einem Exempel ein Script vorgestellt, mit dem es möglich ist, mehrere Ajax-Requests entsprechend einer festgelegten Reihenfolge auszuführen. Im Beispiel auf dieser Seite sollen die Anfragen nicht nur hintereinander gesendet werden, sondern zum Teil parallel. Dabei sollte jedoch bedacht werden, dass die Anzahl von gleichzeitig gesendeten Requests nicht beliebig erhöht werden kann, ohne die vorgegebenen Grenzwerte der verwendeten Browser zu berücksichtigten.
Unter Grenzwerte sind in diesem Zusammenhang die Werte für die Anzahl möglicher paralleler Verbindungen zu einer Domain bzw. die Werte für die Anzahl der gleichzeitigen Verbindungen pro Host-Namen zu verstehen. Lagen diese Werte bei den Browsern früherer Generationen noch bei 2 bis 4 Verbindungen, so hat sich deren Anzahl zwar auf 6 bis 8 erhöht, die maximale Anzahl sollte dennoch nicht unbedingt nur für JavaScript ausgereizt werden, da eine HTML-Seite in der Regel noch weitere referenzierte Quellen zu laden hat, wie CSS-Dateien oder eingebundene Grafiken.
Wer es etwas genauer wissen möchte, der oder diejenige kann unter der Webadresse www.browserscope.org in der Kategorie Network nachschlagen. Nachfolgend eine kleine Übersicht ausgewählter Daten von browserscope.org, wobei der erste Wert für die Anzahl möglicher Verbindungen zu einer Domain steht und der zweite Wert für die maximale Anzahl gleichzeitiger Verbindungen zu unterschiedlichen Domains. Wie bereits auf der letzten Seite beschrieben, ist die Anzahl der möglichen Verbindungen zu unterschiedlichen Hosts für die beschriebenen Beispiele bedeutungslos, da die Browser kein Cross-Site-Scripting mit Ajax ermöglichen.

IE 9  => 6 - 35 
IE 10 => 8 - 16 
FF 18 => 6 - 10 
FF 21 => 6 - 16

Eine weitere Möglichkeit sich zu informieren besteht zum Beispiel darin, in der Adressleiste des Firefox about:config einzugeben und in der sich öffnenden Datei nach dem Eintrag network.http.max-persistent-connections-per-server und dessen Wert zu suchen.

Nicht nur aus diesen Werten, sondern vielmehr noch aus den vielfältigen Berichten in Foren rund um die Projektierung und optimale Gestaltung von Webseiten lässt sich ableiten, dass es weniger darauf ankommt, möglichst viele Anfragen in möglichst kurzer Zeit zu senden und die eintreffenden Antworten zu verarbeiten. Vielmehr kommt es darauf an, die unbedingt erforderlichen Requests und Responses möglichst optimal zu verteilen. Um diesem Ziel etwas näher zu kommen, können zum Beispiel kleinere Bilder zu einem größeren Bild zusammengefasst werden, um dann mit Hilfe von CSS-Sprites nur den jeweils gewünschten Teilausschnitt wiederzugeben. Doch die Beschreibung derartiger Techniken ist nicht Ziel dieses Tutorials.
In diesem Tutorial geht es nur um eine Möglichkeit, eine unbestimmte Anzahl von Ajax-Requests so zu verteilen, dass sich die Gesamtzeit bis zum Eintreffen der letzten Response merklich verkürzt. Für die durchgeführten Tests wurden 8 Seiten von 5 unterschiedlichen Domains ausgewählt. Aus diesen 8 Seiten sollten jeweils nur der Seitentitel und die Description ausgelesen und ausgegeben werden. Auf eine weitere oder unterteilte Aufgabenstellung bei der Verarbeitung wurde aus Gründen der Übersichtlichkeit verzichtet, zumal eine Variante bereits auf der vorausgehenden Seite (Beispiel testseite.php) vorgestellt wurde.

Umsetzung: Serverseitige Kommunikation

Für die Abwicklung der parallel verlaufenden Anfragen und Auswertung der Antworten wurden zwei Proxy-Seiten eingerichtet, die sich vom Code praktisch nicht unterscheiden, mit Ausnahme der im Array enthaltenen Daten.

Beispielseite 1 (proxy-1-4.php):

<?php
ini_set("user_agent", "Mozilla/5.0 (compatible; Proxy-Test +".$_SERVER["HTTP_HOST"].")");

error_reporting(E_ALL);
ini_set("display_errors", true);

$feedurls = array (

    1 => "www.example.com/startseite.html",
    2 => "www.example.com/unterseite1.html",
    3 => "www.example.com/unterseite2.html",
    4 => "www.example.com/unterseite3.php",
);

if (isset($_GET["urlid"]) and !empty($_GET["urlid"])) {

    $urlid = preg_replace("/[^0-9]/", "", $_GET["urlid"]);
    $finde = "http://".$feedurls[$urlid];

    if (($daten = file_get_contents($finde)) != false) {

        if (preg_match("/<title>(?P<titel>.+?)<\/title>/is", $daten, $fund)){
            echo "<b>".htmlspecialchars($fund["titel"], ENT_QUOTES)."</b><br>\n";
        }
        else {
            echo "Es wurde kein Titel gefunden!<br>\n";
        }
        if (preg_match("/<meta.+?description.+?content=\"(?P<descript>.+?)>/is", $daten, $fund)){
            echo htmlspecialchars($fund["descript"], ENT_QUOTES)."<br>\n";
        }
        else {
            echo "Es wurde keine Description gefunden!<br>\n";
        }
    }
}

?>

Zu beachten ist, dass die IDs der URLs durchgängig zu vergeben sind, da diese mit der Erhöhung des Wertes der Variablen i (in der Seite mit dem Ajax-Script parallel.html) und mit den jeweiligen Div-Bereichen für die Ausgabe überein­stimmen müssen.

Beispielseite 2 (proxy-5-8.php):

<?php
// ... Der restliche Code ...

$feedurls = array (

    5 => "www.example.net/startseite.html",
    6 => "www.example.net/unterseite4.html",
    7 => "www.example.net/unterseite5.html",
    8 => "www.example.net/unterseite6.php",
);

if (isset($_GET["urlid"]) and !empty($_GET["urlid"])) {

    // ... Der restliche Code ...
}
?>

Für einen Vergleichstest mit dem Script von der vorausgehenden Seite (ajax.html) wurde noch eine dritte Seite (proxy-1-8.php) eingerichtet, die in einem Array alle 8 Webadressen enthält. Auf die Wiedergabe des Codes wurde verzichtet, da der Code den oben vorgestellten Scripts entspricht. Das Ergebnis des Vergleichstest wird aus den weiter unten eingebundenen Grafiken ersichtlich.

Umsetzung: Clientseitige Kommunikation

Das clientseitige Ajax-Script baut auf dem ebenfalls bereits auf der voraus­gehenden Seite beschriebenen Script auf, mit dem Unterschied, dass die Funktionen sendeRequest() und ladeSeite() noch einmal durch eine dritte Funktion gekapselt wurden. Weiterhin wird die Funktion sendeRequest() nicht mehr direkt von der dem window.onload Event-Handler zugewiesen Funktion aufgerufen, stattdessen die kapselnde Funktion sendeAnfragen(). Mit der Funktion sendeAnfragen() können nun die gewünschten Werte an die inneren Funktionen übergeben werden. Die Reihenfolge der Werte muss bei der Übergabe eingehalten werden.

Demo-Script mit Ajax (parallel.html):

<!DOCTYPE html>
<html>

<head>
<title>Ein Demo-Script mit Ajax</title>
<style type="text/css">
h1 {text-align:center}
div.bereich {width:800px; margin:auto}
div.ausgabe {float:left; border:1px solid #7f4925; width:352px; margin:10px}
</style>
</head>

<body>
<h1>Ein Demo-Script mit Ajax</h1>
<!--
 Hier so viele Div-Bereiche im Dokument anlegen und mit einer ID versehen,
 wie auszuwertende Seiten geladen werden sollen.
-->
<div class="bereich">
    <div id="ausg1" class="ausgabe">01 - </div>
    <div id="ausg2" class="ausgabe">02 - </div>
    <div id="ausg3" class="ausgabe">03 - </div>
    <div id="ausg4" class="ausgabe">04 - </div>
    <div id="ausg5" class="ausgabe">05 - </div>
    <div id="ausg6" class="ausgabe">06 - </div>
    <div id="ausg7" class="ausgabe">07 - </div>
    <div id="ausg8" class="ausgabe">08 - </div>
</div>

<!-- Script-Bereich im Head oder Footer unterbringen oder auslagern -->

<script type="text/javascript">
"use strict";

function sendeAnfragen(start, anzahl, seite) {

    var i   = start;    // Der jeweilige Startwert (Kommentare nur als Info!)
    var anz = anzahl;   // Anzahl der zu ladenden URIs
    var url = seite;    // Die jeweilige Seite des ProxyScripts

    function sendeRequest() {

        var testObj = null;
            testObj = new XMLHttpRequest();

        testObj.open("GET", url+"?urlid="+i);
        testObj.onreadystatechange = ladeSeite;
        testObj.send(null);

        function ladeSeite() {

            if (testObj.readyState == 4 && testObj.status == 200) {
                document.getElementById("ausg"+i).innerHTML += testObj.responseText;
                i++;
                if (i <= anz) sendeRequest();
            }
        }
    }
    sendeRequest()
}

window.onload = function() {

    sendeAnfragen(1, 4, "proxy-1-4.php");
    sendeAnfragen(5, 8, "proxy-5-8.php");
}
</script>
</body>
</html>

Dieses Script wird voraussichtlich nur dann seinen Dienst verrichten, wenn der Gültigkeitsbereich der Variablen beachtet wird und keine Variablen versehentlich als global definiert werden. Eine Kontrolle im Browser mit "use strict" ist bisher nach unserem Kenntnisstand wohl nur mit dem Firefox möglich, von Tools wie JSLint einmal abgesehen.

Vergleichstest

Wie bereits erwähnt, wurden für den Vergleichstest 8 Seiten von 5 unterschied­lichen Domains ausgewählt, dabei einmal mit dem Scripts proxy-1-8.php und ajax.html hintereinander aufgerufen und ausgelesen und einmal mit den auf dieser vorgestellten Scripts. Die Ladezeiten halbierten sich durch die parallele Abarbeitung der Requests und Responses zwar nicht ganz, kamen jedoch dem Ziel sehr nahe. So lag die Zeitlinie der hintereinander ausgeführten Requests im Mittel bei 3,60 Sekunden, die Zeitlinie bei den 2 x 4 Anfragen im Mittel bei 2 Sekunden und darunter.

Zeitlinie der einfachen Ajax-Requests
Zeitlinie der Ajax-Requests mit dem Script ajax.html und einem Script proxy-1-8.php
(8 Anfragen hintereinander in Reihe ausgeführt - im Mittel 3.60 Sekunden)


Zeitlinie der Ajax-Parallel-Requests
Zeitlinie der Ajax-Parallel-Requests mit dem Script parallel.html
und zwei serverseitigen Scripts proxy-1-4.php und proxy-5-8.php
(Ausführung von 2 x 4 Anfragen - im Mittel unter 2,00 Sekunden)
Screenshot-Ausschnitte vom Firebug

Gut zu erkennen ist beim zweiten Screenshot, dass die Anfragen nur zeitgleich beginnen, dann zwar weiterhin parallel verlaufen, jedoch nicht mehr unbedingt zeitgleich. Die zum onreadystatechange gehörende Funktion für den Event-Handler wird immer dann sendeRequest() erneut aufrufen, sowie die letzte Response eintraf, wodurch es zu einem zeitlichen Versatz kommt. Oder einfacher, es feuert immer derjenige zuerst, der als nächstes seinen Vorderlader wieder geladen hat.

Dass es zur unbeabsichtigten Überschreibung von var testObj durch ein anderes XMLHttpRequest Objekt kam oder zu einem "Verhaspeln" nicht zueinander gehörender Requests und Responses, konnte bei den durchgeführten Tests nicht festgestellt werden. Dennoch sollte bei eigenen Tests vor dem praktischen Einsatz darauf geachtet werden, um mögliche Fehlerquellen auszuschließen.

Mehr zum Thema Einbinden und Einlesen von Dateien mit HTML, PHP und
JavaScript auf den folgenden Seiten.

weiterlesen: 1, 2, 3, 4, 5 « / »

 
Navigation

Finden und
gefunden werden ...


- Optimierung -

 

Webcoding

Übersicht


Web Services


Tutorials &
diverse Listings

und vieles mehr...

 

Weitere Themen

Übersicht


Copyright © 2006 - Verlag Horst Müller - Stendal | Datenschutz | Nutzungsbedingungen