Zum Jahresabschluss holten wir uns mal wieder den Kahlil ins Haus und besprachen mit ihm das Konzept der reaktiven funktionalen Programmierung anhand der JavaScript-Frameworks cycle.js, Rx und Bacon.js.
Schaunotizen
- [00:00:13] Reaktive funktionale Programmierung
-
- Reactive Extensions
- Cycle.js
- Bacon.js
- Observables: Collections auf einer Zeitleiste zur Datentransformation
- Kahlil: „Es ist wie Rohre legen“
- Talk zu Cycle: What if the user was a function?
- Slides zu Bacon: Functional Reactive Programming and Bacon.js
- MVI-Pattern, Komponenten, React
- Grundlagen funktionaler Programmierung
[01:14:37] Keine Schaunotizen
- postcss-bem-linter
- A BEM linter for postcss
- stylelint
- A mighty, modern CSS linter that helps you enforce consistent conventions and avoid errors in your stylesheets.
- Descriptive
- Podcast zum Thema „Programmer Origin Stories“
- Reactive
- „A podcast in which we merge, filter, scan and map streams of thoughts and talk about software engineering, culture, and technology.“
Kommentare
Laszlo Korte #
Geschrieben am 1.01.2016 um 03:37
Schöner Podcast.
Auch wenns dazu online ja schon einige Artikel gibt, noch mal ein kurzer Versuch auf die Thematik der Cold vs Hot Observables einzugehen, da es hierbei ja zu einiger Verwirrung kam:
Hot Observables sind offenbar sehr einfach zu verstehen, da sie sehr ähnlichem einem EventBus oder dem klassischen Observer-Pattern funktionieren: Aus irgendeinem Grund (Benutzerinteraktion, Timer, Network-Requests…) treten Events auf. Es gibt die Möglichkeit sich bei dem entsprechenden Observable als Subscriber anzumelden. Wer das tut wird ab dem Zeitpunkt der Anmeldung über alle folgenden Events informiert. Alle Events die vor der Anmeldung passiert sein könnten sind aus Sicht eines späteren Subscribers nicht existent.
Cold Observables funktionieren prinzipiell etwas anders. Während die meisten Hot Observables nur eine Umwandlung von „echten Events“ aus der „Außenwelt“ vornehmen (z.B: DOM-Events oder Network-Requests, die im Prinzip auch existieren ohne dass überhaupt ein Observable erzeugt wird, was wie als Stream bündelt), sind Cold Observables in der Lage ihre Werte selbst zu erzeugen. z.B. ein Observable was wie im Podcast genannt aus einem Array mit 15 Werten erzeugt wurde, kennt diese Werte schon von Beginn an. Genau so wie ein Observable was alle 500ms einen Wert erzeugt. Dieses kennt zwar nicht von Beginn an *alle* Werte, die im Laufe der Zeit Erzeugt werden, aber besitzt alle Informationen, die zur Erzeugung der Werte nötig sind.
Ein Cold-Observable hängt also nicht von externen Events ab, sondern erzeugt seine Werte selbst und schickt diese an die Subscriber. Und wann tut es das? Sobald ein Subscriber sich anmeldet.
Was passiert nun wenn zwei oder Subscriber sich anmelden? Dann werten die Werte mehrfach erzeugt und gesendet – an jeden Subscriber getrennt von einander.
Wenn wir nun also ein Cold Observable haben, was bei 1 startend, jede Sekunde einen um 1 erhöhten Wert erzeugt, dann tut es dass für jeden seinen Subscriber.
Wenn der erste Subscriber sich anmeldet, wird ein Timer gestartet, der nach einer Sekunde den ersten Wert liefert, dann nach noch einer Sekunde den nächsten etc…
Wenn nun ein zweite Subscriber sich bei diesem Observable anmeldet, wird *für diese Anmeldung* ein komplett neuer Timer gestartet, der wieder bei 1 beginnt und dessen Zeit ab dem Zeitpunkt der Anmeldung läuft.
Auch Ajax-Requests oder DOM-Events lassen sich als Cold Observable Modellieren.
Ein „Cold Ajax Observable“ wäre eines, was für jeden einzelnen Subscriber zum Zeitpunkt der Anmeldung einen Request startet und die jede Response jeweils an den entsprechenden Observable sendet.
ein „Cold DOM Observable“ würde für jeden Subscriber einen neuen Listener per addEventListener beim DOM Anmelden und jeweils die auftretenden Events an den einen Subscriber senden.
Man kann daher auch sagen, dass Cold observables lazy sind, weil sie den gesamten Setup Prozess, der dazu führt, dass überhaupt Events entstehen, die dann „durch die Rohre fließen“ erst vornehmen, wenn ein Subscriber sich anmeldet und dieses Setup dann aber sogar für jeden Subscriber getrennt von einander vornehmen.
Im Podcast wird ein einer Stelle gesagt, dass per share() oder shareReplay() ein Hot Observable in ein Cold Observable gewandelt werden kann, aber es ist genau anders rum:
share() und shareReplay() wandeln einen Cold Observable in einen Hot Observable indem quasi eine einzelne Subscription mit mehreren weiteren Subscribern „geshared“ wird. Der Setup wird also nur einmal vorgenommen (Event Listener nur einmal binden, Ajax Request nur einmal senden oder Timer nur einmal initialisieren) und die dann entstehenden Events werden mit mehreren Subscribern geteilt/werden gebroadcasted.
Eine andere Analogie die auch von André Staltz zu Erklärung von Hot vs Cold verwendet wird ist der vergleich eines normalen Videos auf Youtube und eines Livestreams.
Ein normales Video startet für jeden Betrachter bei 0:00 – egal wann dieser es aufruft – und enthält die gesamten nötigen Informationen. Das wäre ein Cold Observable.
Ein Livestream betrachten alle Zuschauer an der selben Zeitmarke. Ein Später einschaltender Zuschauer kann die verpasste Zeit nicht nachholen(Außer es gibt einen Buffer zum zurückspulen). Das wäre ein Hot Observable.
Die Umwandlung von Hot ind Cold per share() wäre quasi die Live-Übertragung des Betrachten eines normalen Videos.
Cold Observables sind besonders dann praktisch, wenn eine Operation (wie ein Ajax Request) fehlschlagen können und erneut probiert werden soll. Wenn der Observable Cold ist, braucht man sich der Subscriber nur erneut anmelden und der gesamte Request wird erneut ausgeführt (und klappt dann hoffentlich).
Oder eben, wenn der Ajax Request überhaupt erst dann passieren soll, wenn jemand sich auch für die Response interessiert.
Zu beachten bei Cold Observables ist nur, dass durch die Lazy-Eingeschaft auch die gesamte Chain and Transformationen lazy ausgeführt und damit pro Subsriber einmal durchlaufen wird.
transformed = myCold.filter(…).map(…).map(…).reduce(…)
transformed.subscribe(…)
transformed.subscribe(…)
Würde dazu führen, dass jedes Item zwei mal erzeugt wird (einmal für jeden Subscriber) und dann jedes dieser „doppelten“ Items die Filter, Map und Reduce Funktion einmal durchläuft bis es dann bei seinem jeweiligen Subscriber ankommt.
Wenn der myCold Observable also eigentlich 10 Werte erzeugt, erzeugt er bei 2 Subscribern 20 Werte und alle diese 20 Werte werden gefiltert gemapped und reduced.
Wenn man das aus verschiedenen Gründen nicht möchte hilft ein share()
transformed = myCold.filter(…).map(…).map(…).reduce(…).share()
transformed.subscribe(…)
transformed.subscribe(…)
Nun erzeugt myCold wirklich nur noch 10 Werte, egal wieviele Subscriber sich am Ende anmelden, weil es nur noch einen direkten Subscriber gibt (der von der share() Methode angemeldet wird und der dann also Broadcast-Proxy für die anderen Subscriber dient).
Diese 10 Werte durchlaufen dann die Pipeline bis zum share() und werden erste danach dann die beiden nun folgenden Subscriber verteilt.
Der von share() zurückgegebene Observable ist dann Hot, weil er schon bereit und dabei ist Werte zu senden, sobald share() aufgerufen wurde, egal ob sich dafür nun letztendlich Subscriber anmelden.
Schepp #
Geschrieben am 1.01.2016 um 12:03
Hammerkommentar! Danke :)
Peter #
Geschrieben am 1.01.2016 um 15:52
Danke, das habe jetzt sogar ich verstanden :)
Kahlil #
Geschrieben am 2.01.2016 um 16:59
Vieeelen Dank für die Aufklären Lazlo!!!
Kahlil #
Geschrieben am 4.01.2016 um 11:32
*Aufklärung
RSS-Feed zu diesem Beitrag
Kommentare sind für diesen Beitrag geschlossen.