It’s #FrontendFriday – SubSink: Ein sauberer Ausweg aus der Subscription-Hölle

15.05.2020

Reaktive Programmierung und Angular gehen heutzutage Hand in Hand. Einer der häufigsten Fragen, die sich jeder Angular-Entwickler irgendwann in dieser Konstellation stellen wird, ist: Wann und an welcher Stelle soll ich mich von einem Observable unsubscriben?

Wann sollte eine Subscription aufgelöst werden?

Das Angular Framework stellt jedem Entwickler den ngOnDestroy-Callback zur Verfügung, welcher immer dann aufgerufen wird, sobald das DOM-Element der Komponente aus dem übergeordneten DOM-Baum entfernt wird. Der ngOnDestroy-Callback ist somit für sämtliche Aufräumarbeiten prädestiniert. Wird eine Komponente zerstört, heißt es jedoch nicht zwingend, dass eine automatische Abmeldung von den zugehörigen Datenströmen stattfindet. Es entstehen sogenannte „Ghost-Subscriptions“, welche den Memory vollspammen. Näher betrachtet, kann eine Parallele zwischen einem Ghostbuster und einem Angular-Entwickler gezogen werden, welcher für das Einfangen der Geister zuständig ist. Na ja, sehr Abstrakt…

Soll immer unsubscribed werden?

Im Netz existieren verschiedene Meinungen zu dieser Frage. Besonders bei den sogenannten endlichen Datenströmen gibt es regelrechte Auseinandersetzungen. Ein Beispiel für einen solchen endlichen Observable stellt ein HTTP-Request im Angular-Umfeld dar. Dieser wird nach dem Empfangen des ersten Wertes completed/aufgelöst. Viele Entwickler sind deshalb der Meinung, dass es bei einer solchen Art von Datenströmen zu keinen Memory-Leaks kommen könnte. Wäre sehr nice! Lasst uns mal gezielt versuchen, auch in diesem Fall, einen Geist zu erzeugen. Doch wie? Die Antwort auf diese Frage ist sehr einfach. Wir lösen einen HTTP-Request aus und bevor er completed, navigieren wir zwischenzeitlich in eine andere Komponente. Ich würde sagen, dass Böse hat damit gesiegt.

D.h. die klare Empfehlung: unsubscibe, unsubscribe, unsubscribe… Die Performance wird es uns danken. Bei genauer Betrachtung der folgenden Grafik fällt uns direkt auf, dass es sich hierbei immer wieder um den gleichen Code im ngOnDestroy-Callback handelt.

Abstrakte Darstellung der Unsubscribe-Logik

Gibt es eine elegantere Lösung?

Auf der diesjährigen NG-Conference wird immer wieder das NPM-Paket SubSink in diesem Zusammenhang empfohlen. Das vom Ward Bell entwickelte Paket ist ein einfacher Store zur Aufnahme von RxJS-Oberservables in einer Array Struktur. Mit dieser ist es sehr einfach möglich, unsere Observables zu managen. Alain Chautard, ein von Google zertifizierter Expert Developer in Angular, fasst in seinem Artikel die Funktionalität von SubSink sehr gut zusammen. Folgend eine Grafik, angelehnt an seinen Artikel (siehe Quelle):

Abstrakte Darstellung des Einsatzes von Subsink

Aus der abstrakten Darstellung wird ersichtlich, dass es zwei Arten gibt, mit den Subscriptions umzugehen. Die Rede ist einerseits von einer einfachen Syntax und andererseits von einer Array-Syntax. Doch bisher haben wir nicht viel gewonnen, oder?

Geht es noch besser?

Ja, es geht. Danke für den Tipp Alain! Mit einem zentralen App-Unsubscribe-Adapter, welcher den ngOnDestroy-Callback implementiert und den einmal deklarierten Sub unsubscribed.

Abstrakte Darstellung des Adapter Patterns in Kombination mit SubSink

Als letztes muss nur noch jede Komponente mit dem Adapter in eine Vererbungshierarchie gebracht werden. Cool, oder?

 

Fazit:

Die Implementierung eines zentralen Subs in Kombination mit einem entsprechenden Adapter ist meiner Meinung nach eine sehr gute Methode für ein elegantes Subscription-Management und sollte auf jeden Fall in den Hinterköpfen von Angular Entwicklern beibehalten werden.

Quellen:

https://www.npmjs.com/package/subsink
https://blog.angulartraining.com/how-to-automatically-unsubscribe-your-rxjs-observables-tutorial-2f98b0560298

Zurück zur Übersicht

Kommentar verfassen

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

*Pflichtfelder

*