Caching
Ab und an kommt es vor, dass auf einer Seite mehrere Komponenten eingebunden werden, die die selben Daten vom Backend benötigen und bei Initialisierung einen HTTP Request stellen. Die Daten werden nicht von der übergeordneten Komponente (der Seite) geladen um das Single-Responsibility Prinzip zu wahren und somit den Code zu vereinfachen. Dabei entstehen aber doppelte HTTP Requests, die vermieden werden sollten.
Im Frontend wird deshalb partiell gecacht. Dafür wird cashew eingesetzt und in app.module.ts
konfiguriert. Die aktuelle Konfiguration sieht vor, dass jeder HTTP Request durch cashew
geht - Responses werden aber nicht gespeichert. cashew
sorgt dafür, dass mehrere parallel gestartete Requests zu einem Request zusammengefasst werden.
Caching mit einer TTL > 0 wird im Frontend bewusst vermieden, da die Invalidierung nicht trivial ist. Es wurde früher mal eingesetzt, hat jedoch zu inkonsistenten Zuständen geführt, die ein neu laden der Anwendung mit F5 erfordert haben.
Zukünftig kann aber überlegt werden, ob bestimmte Daten (Dateien zu Lösungen/Aufgaben) im Frontend gecached werden, wenn es dahingehend Optimierungsbedarf gibt.
Wiederverwendung von Komponenten
Die Wiederverwendung von Komponenten kann ebenfalls als Caching betrachtet werden. Damit der Zustand von Komponenten bei einer Back-Navigation erhalten bleibt (Scrollposition, Eingabe in Suchmasken etc.), wird eine RouteReuseStrategy
eingesetzt: CustomReuseStrategy
. Eine Whitelist regelt, welche Komponenten dafür in Frage kommen (reuseRoute
-Attribut bei der Konfiguration der Routes).
Eine Wiederverwendung erfolgt nur, wenn es sich um eine Back-Navigation über den Button/die Aktion im Browser handelt. Komponenten bleiben so lange im Speicher erhalten, bis eine Wiederherstellung (durch Back-Navigation) erfolgt. Wenn die Komponente erneut (über einen anderen Weg) instanziiert wird, erfolgt keine Wiederherstellung. Dies entspricht dem erwarteten Verhalten (wenn man traditionelle Webanwendungen gewohnt ist).
Zu beachten ist, dass wiederverwendete Komponenten die Lifecycle Hooks onAttach
/onDetach
aus der Schnittstelle ComponentWithOptionalLifecycleHooks
berücksichtigen, sodass bei Deaktivierung Observables pausiert und später wieder fortgesetzt werden. Andernfalls lösen diese weiter aus, obwohl die Komponente nicht mehr im Vordergrund steht und führen zu (evtl. zunächst unerklärlichen) Seiteneffekten in anderen Komponenten.
Als Alternative könnten State-Management Ansätze (wie Stores von NgRx) verwendet werden, das ist jedoch mit erheblichem Aufwand verbunden.