Long Polling mit jQuery und PHP: Tutorial.

22. Oktober 2013 · Kategorien: Internet, PHP, Webentwicklung

jquery

Dieses Tutorial wird Dir erklären, wie Du Long Polling (= Comet) mit Hilfe von jQuery und PHP umsetzt. Die Implementierung ist zwar relativ einfach, allerdings gibt es doch einiges zu beachten.

Was ist Long Polling aka Comet?

Nehmen wir als klassisches Beispiel eine Chatsoftware, die wir allein mit PHP und JavaScript umgesetzt möchten.
Wenn Person A mit Person B chattet, muss die Chatsoftware dafür sorgen, dass B möglichst schnell eine Nachricht erhält, sobald A eine Nachricht abgesendet hat.
Eine nahe liegende Lösung wäre es, mit Hilfe von window.setTimeout alle paar Sekunden einen neuen Request abzusenden, der überprüft, ob eine neue Nachricht in der Datenbank liegt.

function checkForNewMessages()
{
	$.ajax({
		type: "POST",
		url: "chat.php"
	}).done(function(result) {
		if(result.messageReceived) {
			... Nachricht wurde empfangen ...
		}
	});
		
	window.setTimeout(function() {
		checkForNewmessages();
	}, 10000);
};

checkForNewMessages();

Das hat zwei starke Nachteile:
Zum einen erhält der Benutzer die Nachricht nur verzögert. Würden wir also das Zeitintervall für window.setTimeout auf 10 Sekunden stellen (was schon sehr kurz ist), erhält Person B im schlimmsten Fall erst 10 Sekunden zu spät die Nachricht.
Ein weiterer Nachteil ist, dass mit jedem Request eine Verbindung zum Server aufgebaut werden muss. Das ist sehr teuer, da jedes Mal diverse Vorgänge stattfinden müssen, bevor die eigentliche Überprüfung durchgeführt werden kann.
Zum Beispiel muss jedes Mal überprüft werden, ob der Benutzer eingeloggt ist. Wenn ein Framework benutzt wird, werden jedes Mal alle benötigten Schritte zur Initialisierung durchgeführt.

Mit Hilfe von Comet bzw. Long Polling ist es möglich, diese Nachteile allein mit jQuery und PHP zu umgehen.

Wie funktioniert Long Polling?

Long Polling bedeutet, dass eine Verbindung zum Server aufrecht erhalten wird. Und zwar so lange, bis das gewünschte Ereignis – in unserem Beispiel das Empfangen einer Chatnachricht – in Kraft tritt.
Solange das nicht passiert ist, bleibt die Verbindung bestehen. Es findet also im Normalfall nur ein Request pro Nachricht statt.

Der jQuery-Code sieht nun so aus:

function checkForNewMessages()
{
	$.ajax({
		type: "GET",
		url: "chat.php",
		timeout: 300000
	}).done(function(result) {
		if(result.messageReceived) {
			... Nachricht wurde empfangen ...
		}
		
		checkForNewMessages();
	});
};

checkForNewMessages();

Viel hat sich nicht geändert. Der Unterschied ist, dass wir die Funktion checkForNewMessages nun erst wieder aufrufen, wenn wir eine Antwort vom Server erhalten haben. Da wir nicht mehr alle paar Sekunden eine neue Abfrage senden müssen, brauchen wir auch keinen Gebrauch mehr von window.setTimeout zu machen.
Wir geben noch einmal explizit das Timeout sehr hoch an (im Beispiel 5 Minuten), sodass das Request nicht vorzeitig abgebrochen wird.
Der PHP-Code, im Beispiel also die chat.php sieht so aus:

if(session_id())
{
	session_close();
}

$message = null;
while(!$message)
{
	sleep(5);
	$message = liesNeueNachichtAusDatenbank();
}

Solange keine Nachricht empfangen wurde, ist $message = null. Das heißt, die while-Schleife wird dann wieder durchlaufen. Wir nutzen sleep(5), um zwischen jeder Datenbankabfrage 5 Sekunden zu warten. Das hat zwar zur Folge, dass der Benutzer im schlimmsten Fall 5 Sekunden auf eine neue Nachricht warten müsste, allerdings können wir dieses Intervall relativ niedrig ansetzen. Eine gut optimierte Datenbankabfrage (mit Indezes) kostet nämlich nicht viel.

Gegebenenfalls ist es wichtig, dass wir die Session schließen!
Es ist nämlich so, dass ein Webserver, beispielsweise Apache, weitere Requests sperrt, während ein Request auf die Session zugreift. Auf diese Weise werden Race Conditions vermieden.
Das heißt, für den Benutzer würde keine weitere Seite laden (zum Beispiel in einem neuen Tab), bevor das Long Polling Request nicht abgeschlossen wurde.

Long Polling Requests debuggen

Um Long Polling Requests zu debuggen, empfehle ich euch Firebug für Firefox oder Chrome. In den Webentwicklertools (F12 unter Windows/Linux bzw. CMD + alt + I auf dem Mac). Dort könnt ihr im Netzwerk-Tab in den XHR-Requests sämtliche Requests einsehen, die von einer Webseite ausgehen. Long Polling Requests stehen für gewöhnlich lange Zeit auf “Pending”. Das bedeutet, der Browser wartet noch auf eine Antwort.

Bitte schreibe ein Kommentar, wenn Du etwas nicht verstehst oder Anmerkungen hast. Ich helfe gerne.

Autor: | Kategorien: Internet, PHP, Webentwicklung

3 Kommentare zu Long Polling mit jQuery und PHP: Tutorial.

  1. Was würdest du machen wenn der User während des “Long Polling” die Seite neu lädt?

    • Christian Kilb sagt:

      Das ist überhaupt kein Problem, wenn man das Long Polling beim nächsten Seitenaufruf erneut startet. Angenommen, ein User besucht eine unserer Webseiten. Nun starten wir Long Polling, um auf ein Ereignis E zu warten. Der Benutzer verweilt 1 Minute auf dieser Seite, danach lädt er die Seite neu, was 5 Sekunden dauert. Danach verweilt er wieder 1 Minute auf der Seite. Wenn das Ereignis innerhalb der ersten Minute eintrifft, gibt es kein Problem. Der Benutzer wird ja rechtzeitig informiert, dass E in Kraft getreten ist. Wenn E in der 2. Minute eintrifft, gibt es auch kein Problem. Und wenn E in den 5 Sekunden eintrifft, während der User die Seite neu lädt, ist das auch kein Problem: Er wird informiert, sobald die Seite fertig geladen ist und wir das Long Polling erneut starten. Wichtig ist eben nur, dass das Long Polling erneut gestartet wird, sobald es abgebrochen ist (durch Timeout oder durch einen Seitenwechsel). Konnte das deine Frage beantworten?

  2. Sebi sagt:

    Wie ist das mit dem Timeout?
    So wie ich das verstehe wird das polling nach 300000 ms abgebrochen.
    Startet es dann anschließend erneut oder muss ich mittels .fail() die funktion erneut starten?

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *