21. April 2016 von Sebastian Müller
Der User ist ein Stream – Reaktive Web UIs mit RxJS
Mit den sogenannten Reactive Extensions für JavaScript (kurz RxJS) können diese Ereignisse als Stream behandelt werden, wodurch man auf Patterns der reaktiven Programmierung zurückgreifen kann:
RxJS wird führend von Netflix entwickelt und ist dort auch produktiv im Einsatz. Aktuell wird an einem kompletten Rewrite von RxJS auf TypeScript-Basis gearbeitet. Die neue Version 5 befindet sich derzeit noch im Beta Status.
Die Reactive Extensions gibt es ebenfalls in vielen anderen Programmiersprachen.
Das Observable als Grundbaustein
Schauen wir auf ein kleines Code-Beispiel, das die Grundlagen von RxJS zeigt:
import {Observable} from 'rxjs/Observable';
const observable = new Observable((observer) => {
setTimeout(() => {
observer.next(1);
}, 1000);
setTimeout(() => {
observer.next(2);
}, 2000);
setTimeout(() => {
observer.complete();
}, 3000);
});
observable.subscribe(
(value) => {
console.log('Neuer Wert:', value);
},
(message) => {
console.log('Error Fall: ', message);
},
() => {
console.log('Complete Fall - es werden keine neue Werte emitted');
}
);
Die Ausgabe in der Browserconsole zu diesem Beispiel sieht wie folgt aus:
Im oben dargestellten Beispiel wird ein sogenanntes Observable erzeugt, das als Grundbaustein von RxJS zu verstehen ist. Der sogenannte Observer hat die Möglichkeit, über einen undefinierten Zeitraum n Ereignisse auszulösen (observer.next()). Mit einem observer.complete()-Aufruf kann man den Stream als beendet kennzeichnen. Nach diesem Aufruf können keine neuen Werte mit observer.next() emitted werden.
Ein erzeugtes Observable stellt eine subscribe()-Methode bereit, mit der man sich über folgende drei Dinge informieren lassen kann:
- Ein neuer Wert wurde emitted (1. Argument).
- Es gab einen Fehler (2. Argument).
- Der Stream ist beendet (3. Argument).
Die Subscribe-Methode eines Observables kann beliebig oft aufgerufen werden.
Warum Promises nicht ausreichend sind
Seit ECMAScript 2015 (auch bekannt als ES6) sind Promises zum JavaScript-Standard aufgestiegen, die eine simple API für asynchrone Operationen bereitstellen. Jedoch haben Promises im Vergleich zu Observables einige Einschränkungen:
- Sie können nur ein Ergebnis zurückliefern.
- Sie können nicht abgebrochen werden.
Dass Promises nur ein Ergebnis zurückliefern können, mag bei einem simplen XMLHttpRequest kein Problem darstellen, da der Server auch nur eine Antwort liefert. Jedoch sieht es bei Websocket Connections oder auch Browserevents wie z.B. Clicks und Tastatureingaben schon anders aus. Dort gibt es über einen meist undefinierten Zeitraum n Werte/Ereignisse, mit denen man umgehen möchte. In diesen Fällen sind die Reactive Extensions die richtige Option und weitaus flexibler als klassische Callback-Funktionen. Sie sind genau für diese Fälle konzipiert worden und stellen viele nützliche Methoden zur weiteren Verarbeitung bereit.
Selbst bei klassischen XMLHttpRequests bieten Observables gegenüber Promises den Vorteil, dass die Requests vorzeitig abgebrochen werden können. Dies kann nützlich sein, wenn der User Aktionen auf der Oberfläche ausführt, die eine Beendigung eines noch laufenden XMLHttpRequests überflüssig machen.
RxJS als fester Bestandteil von Angular 2
Eine weitere Entwicklung ist die Integration von RxJS in Angular 2. Das populäre Framework wird auf die neue RxJS Version 5 setzen, die sich wie Angular 2 ebenfalls noch im Beta-Status befindet und ein kompletter Rewrite auf TypeScript-Basis ist.
Der Weg zum ECMAScript-Standard
In Zukunft könnten die Observables sogar zum ECMAScript-Standard werden und so könnte es zu einer nativen JavaScript-Version kommen. Ein entsprechendes Proposal ist bereits in Arbeit und auf Github verfügbar. Es bleibt abzuwarten, wie die entsprechenden APIs aussehen werden und welchen Funktionsumfang sie bieten.
Fazit
RxJS stellt eine sehr mächtige Library dar, die das Arbeiten mit asynchronen Operationen im Javascript-Bereich erheblich erleichtern kann und den Sourcecode leserlicher macht. Die Einarbeitung in die reaktive Programmierung und den RxJS-Konzepten kostet nicht wenig Zeit, die aber auf lange Sicht gut investiert ist. Durch die gute Integration mit Angular 2 und anderen JavaScript Frameworks/Libraries wird RxJS in der nächsten Zeit sicherlich noch populärer werden. Spannend bleibt die Frage, ob die Observables in den ECMAScript-Standard aufgenommen werden. Was meint ihr?